排序算法C++实现—八大排序算法

it2022-05-05  168

前言

把排序算法忘光了,回顾《数据结构》严蔚敏版,并看了网上的几篇文章后,随再做一次总结。本文不会具体介绍每一个算法,我觉得要具体看,可以看《数据结构》这本书,写得很好,不懂的再百度补充知识,主要是每一种方式的实现展示出来。

 

他们的性能比较:

排序算法C++实现

1.插入排序

1.1.直接插入排序

/* 直接插入排序 int ai[] 为需要排序的数组 start 为起始位置,要求 start>=1 ,因为 ai[0] 要作为“哨兵”使用。 end 为结束位置 代码思路:看后面的数字有没有比前面的大,比前面的大则需要插入交换,从后往前,依次比较,依次往后移一位,直到不满足 */ void InsertSort(int ai[] , int start , int end) { int i , j ; for(i=start; i<=end; i++){ if(ai[i]<ai[i-1]){ ai[0] = ai[i] ; ai[i] = ai[i-1] ; for(j=i-2; ai[j]>ai[0]; j--){ ai[j+1] = ai[j] ; } ai[j+1] = ai[0] ; } } }

1.2.希尔排序

/** * 希尔排序 * 分组插入排序、时间复杂度取决于所取“增量”序列函数、不稳定 * 增量序列中的值没有除 1 之外的公因子,并且最后一个增量值必须等于 1 。 */ void ShellInsert(int ai[], int start, int end, int dt) { int i, j ; for(i=start+dt; i<=end; i++){ if(ai[i] < ai[i-dt]){ ai[0] = ai[i]; for(j=i-dt; j>0 && ai[0]<ai[j]; j-=dt){ ai[j+dt] = ai[j] ; } ai[j+dt] = ai[0] ; } } }

1.3折半插入排序

/** * 折半插入排序 * 不论初始序列情况如何,在插入第 i 个记录时,需要经过 log2i + 1 次比较 * 折半插入排序仅减少了关键字间的比较次数,而记录的移动次数不变 * */ void BInsertSort(int ai[] , int start , int end) { int i,j ; for(i=start; i<=end; i++){ if(ai[i] < ai[i-1]){ ai[0] = ai[i] ; int low = 1, high = i-1 ; while(low<=high){ int mild = (low + high)/2 ; if(ai[mild] > ai[0]){ high = mild - 1 ; }else { low = mild + 1 ; } } for(j=i-1; j>=high+1; j--){ ai[j+1] = ai[j] ; } ai[j+1] = ai[0]; } } }

2.交换排序

2.1.冒泡排序

/** * 冒泡排序 * 两两比较相邻数的大小,逆序则交换,从而使最小的数如气泡一般逐渐上升,或者最大的数逐渐“坠落“ * int a[]为需要排序的数组 * start为起始位置,要求start>=1 * end为结束位置 */ void BubbleSort(int ai[], int start, int end) { bool flag = true ; for(int i=start; i<=end-1 && flag; i++) { flag = false ; for(int j=start; j<=end-i; j++){ if(ai[j] > ai[j+1]){ flag = true ; int t = ai[j]; ai[j] = ai[j+1]; ai[j+1] = t; } } } }

2.2.快速排序

/** * 快速排序 * 一次排序消除多个逆序 * 递归,分治法 */ int Partition(int ai[], int low, int high) { int privotkey = ai[low]; while(low<high){ while(low<high && ai[high] >= privotkey) high--; ai[low] = ai[high]; while(low<high && ai[low] <= privotkey) low++; ai[high] = ai[low]; } ai[low] = privotkey; return low; } void Qsort(int ai[], int low, int high) { if(low < high){ int pivotloc = Partition(ai,low,high); // 将 ai 一分为二,pivotloc 是枢轴位置 Qsort(ai, low, pivotloc-1); Qsort(ai, pivotloc+1, high); } }

3.选择排序

3.1.简单选择排序

/** * 简单选择排序 * 找到最小的与相应第一个交换 * */ void SelectSort(int ai[], int start, int end) { for(int i=start; i<end; i++){// n-1 次比较 int k = i ; for(int j=i+1; j<=end; j++){ if(ai[j] < ai[k]) k = j ; } if(k != i){ int t = ai[i] ; ai[i] = ai[k] ; ai[k] = t ; } } }

3.1.堆排序

/** * 堆排序,大根堆,升序,完全二叉树 * 筛选法,初建堆从 n/2 开始从下往上,父节点大于子节点 * 堆排序,调整堆,从 1 往下,交换了则需要继续往下递归,否则跳出。 * 最坏O(nlog2n),而快排最坏O(n^2),当记录较多时较为高效 */ void HeapAdjust(int ai[],int start,int end) { int rc = ai[start] ; for(int i=2*start; i<=end; i*=2){ if(i < end && ai[i] < ai[i+1]) i++; if(rc > ai[i]) break ; ai[start] = ai[i]; start = i; } ai[start] = rc ; } void CreateHeap(int ai[],int end) { for(int i=end/2; i>0; i--){ HeapAdjust(ai,i,end) ; } } void HeapSort(int ai[],int end) { CreateHeap(ai,end); for(int i=end; i>0; i--){ ai[0] = ai[1]; ai[1] = ai[i]; ai[i] = ai[0]; HeapAdjust(ai,1,i-1) ; } }

4.归并排序

/** * 归并排序 * int ai[]为需要排序的数组 * cnt为求逆序对数目,是归并排序的拓展 */ int cnt = 0 ; // 合并 ai 数组,排好序,临时存放在 temp 数组里,然后再拷贝到原来的数组 ai void Merge(int ai[], int L, int mild, int R) { int *temp = new int[R-L+1] ; int k = L, i = L, j = mild + 1 ; while(i<=mild && j <= R){ if(ai[i]<=ai[j]) temp[k++] = ai[i++]; else{ temp[k++] = ai[j++]; cnt += mild - i + 1 ; /** * 举个例子: A=1,4,6,7,9 B=2,3,5,10,13,21.在Merge中发现当前i号元素4比2大,那么4的逆序数需要+1,又因6,7,9都排在4后面,那么6,7,9的逆序数也应该+1, * 所以总体的逆序数应该加上last-i+1.(如果i号元素比B[j]小(比如4比5小),无法确定逆序数的变化,不作任何修改). */ } } while(i<=mild) temp[k++] = ai[i++] ; while(j<=R) temp[k++] = ai[j++]; for(int i=L;i<k;i++){ ai[i] = temp[i] ; } } // 归并排序,将 ai 数组前半部分后半部分分成最小单元,然后在合并 void MergeSort(int ai[], int L, int R) { if(L==R){ return ; } else { int mild = (L + R) / 2 ; MergeSort(ai,L,mild); MergeSort(ai,mild + 1, R); Merge(ai,L,mild,R); } }

5.基数排序

/** * 基数排序 * 分配 + 收集 * 分配:我们将 ai[] 中的元素取出,首先确定其个位上的数字,根据该数字分配到与之序号相同的桶中 range * 收集:当序列中所有的元素都分配到对应的桶中,再按照顺序依次将桶中的元素收集形成新的一个待排序列 ai[ ] * 需要知道各级关键字的主次关系和各级关键字的取值范围 */ void countSort(int ai[], int exp, int len) { vector<int> range[10] ; for(int i=1; i<=len; i++){ // 分配 int t = (ai[i]/exp) ; range[t].push_back(ai[i]); } int ant = 1 ; for(int i=0; i<10; i++){ // 收集 for(int j=0;j<range[i].size();j++){ ai[ant++] = range[i][j] ; } } } void RadixSort(int ai[],int start, int end) { int maxn = -1 ; int len = end - start + 1 ; for(int i=start; i<end; i++){ // 提取出最大值 maxn = max(maxn,ai[i]) ; } for(int exp=1; (maxn/exp)> 0; exp*=10){ countSort(ai,exp,len) ; } }

主函数

int main() { int ai[] = {0,49,38,65,97,76,13,27,49}; /** * 插入排序 * InsertSort(ai,2,8) ; // 直接插入排序 * BInsertSort(ai,2,10) ; // 折半插入排序 * ShellSort(ai,1,10); // 希尔排序 */ /** * 交换排序 * BubbleSort(ai,1,10) ; // 冒泡排序 * Qsort(ai,1,10) ; // 快速排序 */ /** * 选择排序 * SelectSort(ai,1,10); // 简单选择排序 * HeapSort(ai,8) ; // 堆排序 */ /** * MergeSort(ai,1,8) ; // 归并排序 * RadixSort(ai,1,8) ; // 基数排序 */ for(int i=1;i<=8;i++){ cout<<ai[i]<<" "; } cout<<endl; return 0 ; }

参考

《数据结构》严蔚敏版

数据结构常见的八大排序算法(详细整理)


最新回复(0)