前面,我们已经学习了数据结构中的各种知识
那么接下来,我们学习排序。之前我们了解过一些排序,其中最熟悉的就是冒泡排序了。
在日常生活中,排序无处不在
一.直接插入排序
是最简单的排序方法,将一条数据插入到已经排好的有序表中,从而得到一个新的,数据量增加1的有序表
最好从后往前比
1.图示
1.先看第一个数,将数组划分为有序部分和无序部分
看第一个数2,一个数一定是有序的,所以将2划分为有序,后面都是无序
2.无序部分的首个插入到有序部分
取出无序部分的首个,在有序部分从后向前比较,插入到合适的位置
3.重复第二步直到无序部分全部插入有序
8需要比较一次
3要比较多次,注意是多次比较,直接插入,不是比较一次插入一次(与冒泡排序不同)
后面一直比较,插入,重复直到无序部分全部到有序
2.代码实现
从上面的图示中可以看出来,这个算法是遍历一遍所有数然后分别插入,第一个数是有序的,不要排,所以需要n-1次遍历
#include<bits/stdc++.h>
using namespace std;
void InsertSort(int a[],int l)
{
int temp;
int j;
for(int i=1;i<l;i++)
{
if(a[i]<a[i-1])
{
temp=a[i];
for(j=i-1;j>=0&&temp<a[j];j--)
{
a[j+1]=a[j];
}
a[j+1]=temp;
}
for(int k=0;k<l;k++)
cout<<a[k]<<" ";
cout<<endl;
}
}
int main()
{
int a[10]={2,5,8,3,6,9,1,4,7};
int b[10]={1,2,3,4,5,6,7,8,9};
int len=9;
InsertSort(a,len);
return 0;
}
时间复杂度(最坏)O(N^2)--逆序
时间复杂度(最好)O(N)--顺序
与冒泡排序相比,插入更好
冒泡排序的实现
void BubbleSort(int* a, int n)
{
for (int j = 0; j < n; ++j)
{
bool exchange = false;
for (int i = 1; i < n-j; i++)
{
if (a[i - 1] > a[i])
{
int tmp = a[i];
a[i] = a[i - 1];
a[i - 1] = tmp;
exchange = true;
}
}
if (exchange == false)
{
break;
}
}
}
二.希尔排序
1.预排序(接近有序)
2.插入排序
间隔为gap分为一组,总计gap组
预排序:对gap组数据分别(插入)排序
上图中,9,6,3,0是一组;8,5,2是一组;7,5,1是一组;那么结果就是
也就是0 2 1 3 5 7 6 8 4 9,达到了预排序的效果--接近有序
void ShellSort(int* a, int n)
{
// 1、gap > 1 预排序
// 2、gap == 1 直接插入排序
int gap = n;
while (gap > 1)
{
gap = gap / 3 + 1; // +1可以保证最后一次一定是1
// gap = gap / 2;
for (int i = 0; i < n - gap; ++i)
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
if (a[end] > tmp)
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = tmp;
}
}
}
gap越大,跳的越快,越不接近有序(gap=1有序)--大大的数可以更快的到后面,小的数越快到前面
gap越小,大的小的挪动越慢,越接近有序
gap==1是插入排序
gap没有规定的数,但是通常n/3+1(保证最后是1)比较合适
时间复杂度:O(N)
三.选择排序
从待排序的数据中选出最小的和最大的,然后最小的往前放,最大的往后放,重复执行,直到待排数据全部完成。
void Swap(int* p1, int* p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
void SelectSort(int* a, int n)
{
int begin = 0, end = n - 1;
while (begin < end)
{
int maxi = begin, mini = begin;
for (int i = begin; i <= end; i++)
{
if (a[i] > a[maxi])
{
maxi = i;
}
if (a[i] < a[mini])
{
mini = i;
}
}
Swap(&a[begin], &a[mini]);
// 如果maxi和begin重叠,修正一下即可
if (begin == maxi)
{
maxi = mini;
}
Swap(&a[end], &a[maxi]);
++begin;
--end;
}
}
四.堆排序
调整
void AdjustDown(int* a, int n, int parent)
{
int child = parent * 2 + 1;
while (child < n)
{
// 找出小的那个孩子
if (child + 1 < n && a[child + 1] > a[child])
{
++child;
}
if (a[child] > a[parent])
{
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
升序--大堆
/ 排升序
void HeapSort(int* a, int n)
{
// 建大堆
for (int i = (n-1-1)/2; i >= 0; --i)
{
AdjustDown(a, n, i);
}
int end = n - 1;
while (end > 0)
{
Swap(&a[0], &a[end]);
AdjustDown(a, end, 0);
--end;
}
}
五.冒泡排序
void BubbleSort(int* a, int n)
{
for (int j = 0; j < n; ++j)
{
bool exchange = false;
for (int i = 1; i < n-j; i++)
{
if (a[i - 1] > a[i])
{
int tmp = a[i];
a[i] = a[i - 1];
a[i - 1] = tmp;
exchange = true;
}
}
if (exchange == false)
{
break;
}
}
}
六.快速排序
在待排元素序列中任取一个元素作为基准值,按照该排序码将待排集合分割成两个子序列,左子序中的元素均小于基准值,右边的元素均大于基准值,左右子序列重复该工程
// hoare
// [left, right]
int PartSort1(int* a, int left, int right)
{
int keyi = left;
while (left < right)
{
// 右边找小
while (left < right && a[right] >= a[keyi])
{
--right;
}
// 左边找大
while (left < right && a[left] <= a[keyi])
{
++left;
}
Swap(&a[left], &a[right]);
}
Swap(&a[keyi], &a[left]);
return left;
}
挖坑法
// 挖坑法
// [left, right]
int PartSort2(int* a, int left, int right)
{
int key = a[left];
int hole = left;
while (left < right)
{
// 右边找小
while (left < right && a[right] >= key)
{
--right;
}
a[hole] = a[right];
hole = right;
// 左边找大
while (left < right && a[left] <= key)
{
++left;
}
a[hole] = a[left];
hole = left;
}
a[hole] = key;
return hole;
}
前后指针法
// 前后指针法
// [left, right]
int PartSort3(int* a, int left, int right)
{
int prev = left;
int cur = left+1;
int keyi = left;
while (cur <= right)
{
if (a[cur] < a[keyi] && ++prev != cur)
{
Swap(&a[prev], &a[cur]);
}
++cur;
}
Swap(&a[prev], &a[keyi]);
keyi = prev;
return keyi;
}
void QuickSort(int* a, int begin, int end)
{
if (begin >= end)
return;
int keyi = PartSort3(a, begin, end);
// [begin, keyi-1] keyi [keyi+1, end]
QuickSort(a, begin, keyi - 1);
QuickSort(a, keyi+1, end);
}
七.归并排序
void _MergeSort(int* a, int begin, int end, int* tmp)
{
if (begin == end)
return;
int mid = (begin + end) / 2;
// [begin, mid] [mid+1, end]
_MergeSort(a, begin, mid, tmp);
_MergeSort(a, mid+1, end, tmp);
// 归并两个区间
// ...
int begin1 = begin, end1 = mid;
int begin2 = mid+1, end2 = end;
int i = begin;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
tmp[i++] = a[begin1++];
}
else
{
tmp[i++] = a[begin2++];
}
}
while (begin1 <= end1)
{
tmp[i++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[i++] = a[begin2++];
}
memcpy(a+begin, tmp+begin, sizeof(int) * (end - begin + 1));
}