排序算法总结
回到数据结构与算法,再次把一些经典的排序算法的代码回顾一下。
1. 插入排序
可以想象手里有一副扑克牌,从左到右是{4, 3, 7, 1, 9}。一张一张来看。
4
4,3 排序有误。将3插入到4前,变成 3,4。
3,4,7排序无误。
3,4,7,1排序有误,将1插入到3前,变成1,3,4,7
......
代码为:
void swap(int &a, int & b)
{
int temp = a;
a = b;
b= temp;
}
void insertSort(int a[], int length)
{
for(int i=1;i<length;i++)
{
for(int j=i;i>=0;j--)
{
if(a[j-1]>a[j]) swap(a[j-1], a[j]);
}
}
}
特征:原地排序,空间复杂度为O(1)。平均时间复杂度为O(n2),最坏时间复杂度为O(n2)。排序是稳定的。
当基本有序时,使用插入排序效率很高。
2. 冒泡排序
特点就是像冒泡泡一样,一点一点往前移动。总是将当前数与右边数相比,如果当前数更大就和右边的数交换,否则不交换。
例如数组为{4, 3, 7, 1, 9}。
第一轮:{3, 4, 1, 7, 9}
第二轮:{3, 1, 4, 7, 9}
第三轮:{1, 3, 4, 7, 9} 结束
代码如下:
void bubbleSort(int a[], int length)
{
int count = 1;
while(count >0)
{
count = 0;
for(int i=0;i<length-1;i++)
{
if(a[i]>a[i+1])
{
swap(a[i], a[i+!]);
count++;
}
}
}
}
特点:原地排序,空间复杂度为O(1)。时间复杂度为O(n2),最坏时间复杂度为O(n2)。排序是稳定的。
3. 堆排序
关于堆排序介绍众多,此处就不再放图了。主要就是不断交换父节点和子节点来维持有序。
代码如下:
void heapSort(int a[], int length)
{
//从最后一个父节点开始,初始化堆
for(int i = len/2-1;i>=0;i--)
{
heapify(a, i, length);
}
//然后不断将最大值与最后的子节点交换,得到有序序列
for(int i=length-1;i>=0;i--)
{
swap(a[0], a[i]);
heapify(a, 0, i);
}
}
void heapify(int a[], int start, int end)
{
int father = start, son = 2*father + 1;
while(son < end)
{
if(son + 1<end &&a[son] < a[son + 1] ) son++;
if(a[father] > a[son]) break;
else
{
swap(a[son], a[father]);
father = son;
son = father*2 + 1;
}
}
}
特点:原地排序,空间复杂度为O(1)。时间复杂度为O(nlogn),最好时间复杂度最坏时间复杂度都是O(nlogn)。为不稳定排序。
适合求topK问题。
4. 快速排序
简单来说,就是一路从右往左扫掠,另一路从左往右扫掠,一旦遇到违反排序的,就交换。
void quickSort(int a[], int start, int end)
{
if(start>=end) return;
int pivot = onceSort(a, start, end);
quickSort(a, start, pivot-1);
quickSort(a, pivot+1, end);
}
int onceSort(int a[], int start, int end)
{
int i = start, j = end;
while(i<j)
{
while(i<j && a[i]<a[j]) j--;
if(i<j) swap(a[i], a[j]);
while(i<j && a[i]<a[j]) i++;
if(i<j) swap(a[i], a[j]);
}
return i;
}
特点:原地排序,空间复杂度为O(logn)。平均时间复杂度O(nlogn),最坏时间复杂度为O(n2)。排序不稳定。
当数组基本有序时,时间复杂度反而会增加。因此一般在排序前先要打乱来保证高效。
5. 归并排序
典型的二分法排序。
void mergeSort(int a[], const int length)
{
int help[length];
merge(a, help, 0, length-1);
}
void merge(int a[], int help[], int start, int end)
{
if(start>=end) return;
int mid = (start + end)/2;
merge(a, help, start, mid);
merge(a, help, mid+1, end);
int l1 = start, l2 = mid, r1 = mid+1, r2 = end;
int k = l1;
while(l1<=l2 && r1<=r2)
{
if(a[l1]<a[r1])
help[k++] = a[l1++];
else
help[k++] = a[r1++];
}
while(l1<=l2)
help[k++] = a[l1++];
while(r1<=r2)
help[k++] = a[r1++];
for(int k = l1;k<=r2;k++)
a[k] = help[k];
}
特点:借助辅助数组,非原地排序。空间复杂度为O(n)。平均时间复杂度为O(nlogn),最坏时间复杂度也为O(nlogn),为稳定排序。