本文对基本排序算法进行总结,简述其原理,以C++实现。
通用部分:
123456789101112131415161718192021222324252627using namespace std;typedef void (*SortFunc)(int data[],int);//数据交换void DataSwap(int& a,int& b){if (a==b)return;a^=b;b^=a;a^=b;}冒泡排序
思路:依次将剩余最小元素交换到前面
外循环,确定剩余未排序元素的起始位置
内循环,从后向前,相邻两个元素比较,将最小元素交换到未排序起始位置
时间复杂度为o(n^2),需要辅助空间o(1),稳定1234567void BubbleSort(int data[], int len){for(int i=0;i<len-1;++i)for(int j=len-1;j>i;–j)if (data[j]<data[j-1])DataSwap(data[j],data[j-1]);}
改进冒泡排序:若一次内循环中不发生数据交换,则完成所有排序。
|
|
直接选择排序
思路:对于每个位置,分别从后面剩余元素中选择最小的元素交换至当前位置
外循环:确定当前位置
内循环:选择剩余最小元素
时间复杂度为o(n^2),需要辅助空间o(1), 相比冒泡排序算法,交换次数减少 不稳定,例如5 8 5 2 9,第一次5与2交换,第一个5交换至第二个5后面
|
|
直接插入排序
思路:依次将剩余的元素插入到已排好序的元素中
从第二个元素开始,依次与前面的元素两两比较,若较小则交换两个元素,否则进行下一个元素的插入排序
时间复杂度为o(n^2),需要辅助空间o(1),稳定
|
|
希尔排序
从希尔排序开始,出现时间复杂度小于o(n^2)的排序算法
对插入排序进行改进,先子串插入排序,子串基本有序后再插入排序
思路:将相距某个增量的元素子集进行插入排序,逐渐减小增量,再次进行子集插入排序,增量小于1时,停止。
时间复杂度o(n*(logn)^2),需要辅助空间o(1),跳跃式排序,不稳定
实现1:各个子集依次处理
各个子集的第一个元素在0~gap-1位置,作为第一层for循环,各个子集依次处理, 后面两层for循环同插入排序,步长由1变为gap
|
|
实现2:各个元素依次处理
|
|
堆排序
对选择排序进行改进
思路:先构建大顶堆(小顶堆),将第一个元素与最后元素交换,调整剩余元素形成大顶堆(小顶堆),将第一元素与次后元素交换,反复如上操作。
堆元素调整时从最后一个父节点开始,向前调整。
堆排序时间复杂度为o(nlogn),辅助空间复杂度为o(1),跳跃式排序,不稳定
若元素从0开始,则对于节点i,其子节点为2i+1,2i+2,父节点为(i-1)/2取整;
若元素从1开始,则对于节点i,其子节点为2i,2i+1,父节点为i/2取整。12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061void HeapAdjust(int data[],int start, int end){int temp=data[start];//暂存数据int k=start;//坑的位置for (int j=2*start+1;j<=end;j=2*j+1){//取两个子节点中较大节点位置if (j<end && data[j]<data[j+1])//j<end保证存在右节点++j;//若已构成大顶堆,退出调整if (temp>=data[j])break;//子节点与父节点交换,形成大顶堆data[k]=data[j];k=j;}if (k!=start)data[k]=temp;}void HeapSort(int data[], int len){//从最后一个父节点开始,初始化大顶堆for (int i=(len-1)/2;i>0;–i)HeapAdjust(data,i,len-1);//堆排序for(int i=len-1;i>0;–i){DataSwap(data[0],data[i]);HeapAdjust(data,0,i-1);}}
递归实现归并排序
|
|
迭代实现归并排序
|
|
快速排序
思路:通过一次排序,将比一个元素小的元素都放在该元素的一侧,比它大的元素都放在该元素的另一侧,对两侧元素子集同样进行上述操作
时间复杂度为o(nlogn),空间法复杂度为o(logn),跳跃式排序,不稳定
|
|
|
|
|
|