常用排序算法总结(插入、冒泡、选择、希尔、快速、归并、堆)
2017-06-08 16:47
666 查看
简述
插入排序
冒泡排序
选择排序
希尔排序
快速排序
归并排序
堆排序
排序算法稳定性的好处:排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用。例如基数排序,先按低位排序,逐次按高位排序,低位排序后元素的顺序在高位也相同时是不会改变的。
二分插入
(1)直接插入:类似于扑克牌插入,对于未排序数据(右手抓到的牌),在已排序序列(左手已经排好序的手牌)中从后向前扫描,找到相应位置并插入。
空间复杂度:在实现上,需用到O(1)的额外空间,因为在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
具体算法描述如下:
从第一个元素开始,该元素可以认为已经被排序
取出下一个元素,在已经排序的元素序列中从后向前扫描
如果该元素(已排序)大于新元素,将该元素移到下一位置
重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
将新元素插入到该位置后
重复步骤2~5
注意:插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,比如量级小于千,那么插入排序还是一个不错的选择。 插入排序在工业级库中也有着广泛的应用,在STL的sort算法和stdlib的qsort算法中,都将插入排序作为快速排序的补充,用于少量元素的排序(通常为8个或以下)。
(2)二分插入:如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目,称为二分插入排序。
具体算法描述如下:
比较相邻的元素,如果前一个比后一个大,就把它们两个调换位置。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
冒泡排序的改进:鸡尾酒排序:也叫定向冒泡排序。冒泡排序则仅从低到高去比较序列里的每个元素,而鸡尾酒排序是从低到高然后从高到低去比较序列中的每个元素。可以得到比冒泡排序稍微好一点的效能。
选择排序是不稳定的排序算法,不稳定发生在最小元素与A[i]交换的时刻。
注意:插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,比如量级小于千,那么插入排序还是一个不错的选择。 插入排序在工业级库中也有着广泛的应用,在STL的sort算法和stdlib的qsort算法中,都将插入排序作为快速排序的补充,用于少量元素的排序(通常为8个或以下)。
(2)二分插入:如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目,称为二分插入排序。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
- 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
- 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位
基本思想:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。
具体算法描述如下:
以n=10的一个数组49, 38, 65, 97, 26, 13, 27, 49, 55, 4为例
第一次 gap = 10 / 2 = 5,即分成了5组(49, 13) (38, 27) (65, 49) (97, 55) (26, 4),这样每组排序后就变成了(13, 49) (27, 38) (49, 65) (55, 97) (4, 26)
第二次 gap = 5 / 2 = 2,即分成了2组(13,49,4,38,97)(27,55,49,65,26),排序后变成了(4,13,38,49,97)(26,27,49,55,65)
第三次 gap = 2 / 2 = 1,即分成了1组,直接使用插入排序,最后得到(4 13 26 27 38 49 49 55 65 97)
第四次 gap = 1 / 2 = 0 排序完成
对上面的代码进行简化
1. 先从数列中取出一个数作为基准数。
2. 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3. 再对左右区间重复第二步,直到各区间只有一个数。
具体算法描述如下:
例如无序数组[6 2 4 1 5 9]
a. 先把第一项[6]取出来,用[6]依次与其余项进行比较,如果比[6]小就放[6]前边,否则就放[6]后边。排序前 6 2 4 1 5 9,排序后 5 2 4 1 6 9
b. 对前半拉[5 2 4 1]继续进行快速排序,重复步骤a后变成下边这样:
排序前 5 2 4 1,排序后 1 2 4 5
前半拉排序完成,总的排序也完成。
对上面的代码进行整合:
例如无序数组[6 2 4 1 5 9]
第一步 [6 2 4 1 5 9]原始状态
第二步 [2 6] [1 4] [5 9]两两合并排序
第三步 [1 2 4 6] [5 9]继续两组两组合并
第四步 [1 2 4 5 6 9]合并完毕,排序完毕
输出结果[1 2 4 5 6 9]
合并细节
第二步:[2 6] [1 4] [5 9],两两合并,其实仅合并[2 6] [1 4],所以[5 9]不管它
原始状态
第一个数组[2 6]
第二个数组[1 4]
第三个数组[…]
第1步,顺序从第一,第二个数组里取出一个数字:2和1 比较大小后将小的放入第三个数组
第一个数组[2 6]
第二个数组[4]
第三个数组[1]
第2步,继续刚才的步骤,顺序从第一,第二个数组里取数据,2和4,同样的比较大小后将小的放入第三个数组
第一个数组[6]
第二个数组[4]
第三个数组[1 2]
第3步,再重复前边的步骤变成,将较小的4放入第三个数组后变成如下状态
第一个数组[6]
第二个数组[…]
第三个数组[1 2 4]
第4步,最后将6放入,排序完毕
第一个数组[…]
第二个数组[…]
第三个数组[1 2 4 6]
具体算法描述如下:
将一个列表分割成2个子列表
第1个列表调用索引[low,mid]来定义, 第2个列表调用索引[mid+1,high]来定义
将两个有序的子文件R[low..mid)和R[mid+1..high]归并成一个有序的子文件R[low..high]
当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。
堆排序的过程:
1. 创建一个堆
2. 把堆顶元素(最大值)和堆尾元素互换
3. 把堆的尺寸缩小1,并调用从新的堆顶元素开始进行堆调整
4. 重复步骤2,直到堆的尺寸为1
堆排序是不稳定的排序算法,不稳定发生在堆顶元素与A[i]交换的时刻。
插入排序
冒泡排序
选择排序
希尔排序
快速排序
归并排序
堆排序
简述
排序算法的稳定性:如果Ai=Aj,排序前后Ai和Aj的相对位置不变,则称这种排序算法是稳定的,反之,则是不稳定的。排序算法稳定性的好处:排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用。例如基数排序,先按低位排序,逐次按高位排序,低位排序后元素的顺序在高位也相同时是不会改变的。
插入排序
直接插入二分插入
(1)直接插入:类似于扑克牌插入,对于未排序数据(右手抓到的牌),在已排序序列(左手已经排好序的手牌)中从后向前扫描,找到相应位置并插入。
空间复杂度:在实现上,需用到O(1)的额外空间,因为在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
具体算法描述如下:
从第一个元素开始,该元素可以认为已经被排序
取出下一个元素,在已经排序的元素序列中从后向前扫描
如果该元素(已排序)大于新元素,将该元素移到下一位置
重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
将新元素插入到该位置后
重复步骤2~5
// 分类 ---------- 内部比较排序 // 数据结构 ------- 数组 // 最差时间复杂度 -- 输入序列是降序排列的,此时时间复杂度O(n^2) // 最优时间复杂度 -- 输入序列是升序排列的,此时时间复杂度O(n) // 平均时间复杂度 -- O(n^2) // 所需辅助空间 --- O(1) // 稳定性 -------- 稳定 int *insertSort(int *array, int num) { int i, j, target; for(i = 1; i < num; i++) { target = array[i];// 右手抓到一张扑克牌 j = i; while(target < array[j-1] && j >= 1)// 将抓到的牌与手牌从右向左进行比较 { array[j] = array[j-1];// 如果该手牌比抓到的牌大,就将其右移 j--; } //直到该手牌比抓到的牌小或相等,将抓到的牌插入到该手牌右边(相等元素的相对次序未变,所以插入排序是稳定的) array[j] = target; } return array; }
注意:插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,比如量级小于千,那么插入排序还是一个不错的选择。 插入排序在工业级库中也有着广泛的应用,在STL的sort算法和stdlib的qsort算法中,都将插入排序作为快速排序的补充,用于少量元素的排序(通常为8个或以下)。
(2)二分插入:如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目,称为二分插入排序。
int *insertSort(int *array, int num) { int i, j, target; int left, right, middle; for(i = 1; i < num; i++) { target = array[i];// 右手抓到一张扑克牌 left = 0; right = i - 1; while(left <= right)//二分查找过程 { middle = (left + right) / 2; if(array[middle] > target) right = middle - 1; else left = middle + 1; } for(j = i - 1; j >= left; j--)// 右移 { array[j] = array[j-1]; } array[left] = target; } return array; }
冒泡排序
基本思想:依次比较相邻的两个元数,将小的数放在前面,大的数放在后面。具体算法描述如下:
比较相邻的元素,如果前一个比后一个大,就把它们两个调换位置。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
// 分类 -------------- 内部比较排序 // 数据结构 ---------- 数组 // 最差时间复杂度 ---- O(n^2) // 最优时间复杂度 ---- 原始数据有序,在内部循环中使用一个标识来表示有无交换操作,可以把最优时间复杂度降低到O(n) // 平均时间复杂度 ---- O(n^2) // 所需辅助空间 ------ O(1) // 稳定性 ------------ 稳定 int *bubble(int *array, int num) { int i, j, temp; for(i = 0; i < num; i++) { for(j = 0; j < num-i-1; j++) { if(array[j+1] < array[j]) { temp = array[j]; array[j] = array[j+1]; array[j+1] = temp; } } } return array }
冒泡排序的改进:鸡尾酒排序:也叫定向冒泡排序。冒泡排序则仅从低到高去比较序列里的每个元素,而鸡尾酒排序是从低到高然后从高到低去比较序列中的每个元素。可以得到比冒泡排序稍微好一点的效能。
#include <stdio.h> // 分类 -------------- 内部比较排序 // 数据结构 ---------- 数组 // 最差时间复杂度 ---- O(n^2) // 最优时间复杂度 ---- 如果序列在一开始已经大部分排序过的话,会接近O(n) // 平均时间复杂度 ---- O(n^2) // 所需辅助空间 ------ O(1) // 稳定性 ------------ 稳定 void exchange(int A[], int i, int j) // 交换A[i]和A[j] { int temp = A[i]; A[i] = A[j]; A[j] = temp; } int main() { int A[] = { 6, 5, 3, 1, 8, 7, 2, 4 }; // 从小到大定向冒泡排序 int n = sizeof(A) / sizeof(int); int left = 0; // 初始化边界 int right = n - 1; while (left < right) { for (int i = left; i < right; i++) // 前半轮,将最大元素放到后面 if (A[i] > A[i + 1]) { exchange(A, i, i + 1); } right--; for (int i = right; i > left; i--) // 后半轮,将最小元素放到前面 if (A[i - 1] > A[i]) { exchange(A, i - 1, i); } left++; } return 0; }
选择排序
基本思想:遍历列表,并且将最小的元素与第一个元素交换;再次遍历剩余的元素并将次小的元素与第二个元素交换,依次类推。选择排序是不稳定的排序算法,不稳定发生在最小元素与A[i]交换的时刻。
// 分类 -------------- 内部比较排序 // 数据结构 ---------- 数组 // 最差时间复杂度 ---- O(n^2) // 最优时间复杂度 ---- O(n^2) // 平均时间复杂度 ---- O(n^2) // 所需辅助空间 ------ O(1) // 稳定性 ------------ 不稳定 int *selectSort(int *array, int n) { i 1006d nt smallIndex, i, j, temp; for (i= 0; i< n - 1; i++) { // 假定最小值初始时是arr[i]=1st smallIndex = i; // 遍历子列表,从arr[i+1]到arr[n-1],因为从0到i已经是有序的了 for (j = i+ 1; j < n; j++) { //如果发现小元素,把当前元素的索引赋值给最小值 if (arr[j] < arr[smallIndex]) { smallIndex = j; } } //交换 temp = arr[i]; arr[i] = arr[smallIndex]; arr[smallIndex] = temp; } }
注意:插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,比如量级小于千,那么插入排序还是一个不错的选择。 插入排序在工业级库中也有着广泛的应用,在STL的sort算法和stdlib的qsort算法中,都将插入排序作为快速排序的补充,用于少量元素的排序(通常为8个或以下)。
(2)二分插入:如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目,称为二分插入排序。
int *insertSort(int *array, int num) { int i, j, target; int left, right, middle; for(i = 1; i < num; i++) { target = array[i];// 右手抓到一张扑克牌 left = 0; right = i - 1; while(left <= right)//二分查找过程 { middle = (left + right) / 2; if(array[middle] > target) right = middle - 1; else left = middle + 1; } for(j = i - 1; j >= left; j--)// 右移 { array[j] = array[j-1]; } array[left] = target; } return array; }
希尔排序
也叫递减增量排序,是插入排序的一种更高效的改进版本。希尔排序是不稳定的排序算法。希尔排序是基于插入排序的以下两点性质而提出改进方法的:
- 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
- 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位
基本思想:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。
具体算法描述如下:
以n=10的一个数组49, 38, 65, 97, 26, 13, 27, 49, 55, 4为例
第一次 gap = 10 / 2 = 5,即分成了5组(49, 13) (38, 27) (65, 49) (97, 55) (26, 4),这样每组排序后就变成了(13, 49) (27, 38) (49, 65) (55, 97) (4, 26)
第二次 gap = 5 / 2 = 2,即分成了2组(13,49,4,38,97)(27,55,49,65,26),排序后变成了(4,13,38,49,97)(26,27,49,55,65)
第三次 gap = 2 / 2 = 1,即分成了1组,直接使用插入排序,最后得到(4 13 26 27 38 49 49 55 65 97)
第四次 gap = 1 / 2 = 0 排序完成
void shellsort1(int a[], int n) { int i, j, gap; for (gap = n / 2; gap > 0; gap /= 2) //步长 for (i = 0; i < gap; i++) //直接插入排序 { for (j = i + gap; j < n; j += gap) if (a[j] < a[j - gap]) { int temp = a[j]; int k = j - gap; while (k >= 0 && a[k] > temp) { a[k + gap] = a[k]; k -= gap; } a[k + gap] = temp; } } }
对上面的代码进行简化
void shellsort3(int a[], int n) { int i, j, gap; for (gap = n / 2; gap > 0; gap /= 2) for (i = gap; i < n; i++) //从数组第gap个元素开始 for (j = i - gap; j >= 0 && a[j] > a[j + gap]; j -= gap) //每个元素与自己组内的数据进行直接插入排序 Swap(a[j], a[j + gap]); }
快速排序
基本思想:挖坑填数+分治法1. 先从数列中取出一个数作为基准数。
2. 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3. 再对左右区间重复第二步,直到各区间只有一个数。
具体算法描述如下:
例如无序数组[6 2 4 1 5 9]
a. 先把第一项[6]取出来,用[6]依次与其余项进行比较,如果比[6]小就放[6]前边,否则就放[6]后边。排序前 6 2 4 1 5 9,排序后 5 2 4 1 6 9
b. 对前半拉[5 2 4 1]继续进行快速排序,重复步骤a后变成下边这样:
排序前 5 2 4 1,排序后 1 2 4 5
前半拉排序完成,总的排序也完成。
// 分类 ------------ 内部比较排序 // 数据结构 --------- 数组 // 最差时间复杂度 ---- 每次选取的基准都是最大的元素(或者每次都是最小),导致每次只划分出了一个子序列,需要进行n-1次划分才能结束递归,时间复杂度为O(n^2) // 最优时间复杂度 ---- 每次选取的基准都能使划分均匀,只需要logn次划分就能结束递归,时间复杂度为O(nlogn) // 平均时间复杂度 ---- O(nlogn) // 所需辅助空间 ------ O(logn)~O(n),主要是递归造成的栈空间的使用(用来保存left和right等局部变量),取决于递归树的深度,一般为O(logn),最差为O(n)(基本有序的情况) // 稳定性 ---------- 不稳定 int patition(int *array, int low, int high) { int temp = array[low]; while(low<high) { while(low < high && array[high] > temp) high--; array[low] = array[high]; while(low < high && array[low] <= temp) low++; array[high] = array[low]; for(int i = 0; i < high+1; i++) { printf("%d\t",array[i]); } printf("\n"); } array[low] = temp; return low; } int *quick(int *array, int low, int high) { int mid = 0; if(low < high) { mid = patition(array,low,high); quick(array,low,mid-1); quick(array,mid+1,high); } return array; }
对上面的代码进行整合:
void quick_sort(int s[], int l, int r) { if (l < r) { //Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 参见注1 int i = l, j = r, x = s[l]; while (i < j) { while(i < j && s[j] >= x) // 从右向左找第一个小于x的数 j--; if(i < j) s[i++] = s[j]; while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数 i++; if(i < j) s[j--] = s[i]; } s[i] = x; quick_sort(s, l, i - 1); // 递归调用 quick_sort(s, i + 1, r); } }
归并排序
基本思想:将两个或两个以上的有序数据序列合并成一个新的有序数据序列。假设数组A有N个元素,可以将数组A看成是由N个有序的子序列组成,每个子序列的长度为1,然后再两两合并,得到了一个 N/2 个长度为2或1的有序子序列,再两两合并,如此重复,直到得到一个长度为N的有序数据序列为止。例如无序数组[6 2 4 1 5 9]
第一步 [6 2 4 1 5 9]原始状态
第二步 [2 6] [1 4] [5 9]两两合并排序
第三步 [1 2 4 6] [5 9]继续两组两组合并
第四步 [1 2 4 5 6 9]合并完毕,排序完毕
输出结果[1 2 4 5 6 9]
合并细节
第二步:[2 6] [1 4] [5 9],两两合并,其实仅合并[2 6] [1 4],所以[5 9]不管它
原始状态
第一个数组[2 6]
第二个数组[1 4]
第三个数组[…]
第1步,顺序从第一,第二个数组里取出一个数字:2和1 比较大小后将小的放入第三个数组
第一个数组[2 6]
第二个数组[4]
第三个数组[1]
第2步,继续刚才的步骤,顺序从第一,第二个数组里取数据,2和4,同样的比较大小后将小的放入第三个数组
第一个数组[6]
第二个数组[4]
第三个数组[1 2]
第3步,再重复前边的步骤变成,将较小的4放入第三个数组后变成如下状态
第一个数组[6]
第二个数组[…]
第三个数组[1 2 4]
第4步,最后将6放入,排序完毕
第一个数组[…]
第二个数组[…]
第三个数组[1 2 4 6]
具体算法描述如下:
将一个列表分割成2个子列表
第1个列表调用索引[low,mid]来定义, 第2个列表调用索引[mid+1,high]来定义
将两个有序的子文件R[low..mid)和R[mid+1..high]归并成一个有序的子文件R[low..high]
// 分类 -------------- 内部比较排序 // 数据结构 ---------- 数组 // 最差时间复杂度 ---- O(nlogn) // 最优时间复杂度 ---- O(nlogn) // 平均时间复杂度 ---- O(nlogn) // 所需辅助空间 ------ O(n) // 稳定性 ------------ 稳定 //将有二个有序数列a[first...mid]和a[mid...last]合并。 void mergearray(int a[], int first, int mid, int last, int temp[]) { int i = first, j = mid + 1; int m = mid, n = last; int k = 0; while (i <= m && j <= n) { if (a[i] <= a[j]) temp[k++] = a[i++]; else temp[k++] = a[j++]; } while (i <= m) temp[k++] = a[i++]; while (j <= n) temp[k++] = a[j++]; for (i = 0; i < k; i++) a[first + i] = temp[i]; } void mergesort(int a[], int first, int last, int temp[]) { if (first < last) { int mid = (first + last) / 2; mergesort(a, first, mid, temp); //左边有序 mergesort(a, mid + 1, last, temp); //右边有序 mergearray(a, first, mid, last, temp); //再将二个有序数列合并 } } bool MergeSort(int a[], int n) { int *p = new int ; if (p == NULL) return false; mergesort(a, 0, n - 1, p); delete[] p; return true; }
堆排序
二叉堆的定义:二叉堆是完全二叉树或者是近似完全二叉树。当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。
堆排序的过程:
1. 创建一个堆
2. 把堆顶元素(最大值)和堆尾元素互换
3. 把堆的尺寸缩小1,并调用从新的堆顶元素开始进行堆调整
4. 重复步骤2,直到堆的尺寸为1
堆排序是不稳定的排序算法,不稳定发生在堆顶元素与A[i]交换的时刻。
#include <iostream> #include <vector> using namespace std; int heapsize; // 交换A[i]和A[j] void exchange(vector<int> &A, int i, int j) { int temp = A[i]; A[i] = A[j]; A[j] = temp; } // 堆调整函数(这里使用的是最大堆),调整第i个结点 void heapify(vector<int> &A, int i) { int leftchild = 2 * i + 1; // 左孩子索引 int rightchild = 2 * i + 2; // 右孩子索引 int largest; // 选出当前结点与左右孩子之中的最大值 if (leftchild < heapsize && A[leftchild] > A[i]) largest = leftchild; else largest = i; if (rightchild < heapsize && A[rightchild] > A[largest]) largest = rightchild; if (largest != i) //最大值结点不是当前结点i { exchange(A, i, largest); // 把当前结点和它的最大(直接)子节点进行交换 heapify(A, largest); // 递归调用,继续从当前结点向下进行堆调整 } } void buildMaxHeap(vector<int> &num, int n){ heapsize = n; //堆大小 for(int i = heapsize/2-1; i >= 0; i--) // 对每一个非叶结点 heapify(num, i); // 不断的堆调整 } //堆排序 void heapsort(vector<int> &A, int n) { buildMaxHeap(A, n); for(int i=n-1; i >= 1; i--) { exchange(A, 0, i); // 将堆顶元素(当前最大值)与堆的最后一个元素互换(该操作很有可能把后面元素的稳定性打乱,所以堆排序是不稳定的排序算法) heapsize--; // 从堆中去掉最后一个元素 heapify(A, 0); // 从新的堆顶元素开始进行堆调整 } } int main(){ int a[] = {9,12,17,30,50,20,60,65,4,49}; vector<int> num (a,a+10); int len = num.size(); heapsort(num, len); for(int i=0; i<len; i++){ cout<<num[i]<<'\t'; } return 0; }
相关文章推荐
- 10种排序算法总结(冒泡、选择、插入、希尔、归并、快速、堆、拓扑、锦标赛、基数)
- C++排序算法总结(冒泡、插入、选择、希尔、归并、快速、堆)
- 七种排序算法总结(冒泡、插入、选择、希尔、归并、堆、快速)
- 10种排序算法总结(冒泡、选择、插入、希尔、归并、快速、堆、拓扑、锦标赛、基数)
- 序算法总结——冒泡,快速,选择,插入,希尔,归并
- 常见排序算法总结与实现(冒泡、插入、选择、希尔、堆排序、归并、快排)
- 排序算法大集合,插入、选择、冒泡、希尔、堆、归并、快速排序,总有一款适合你
- 十种排序算法总结(冒泡、插入、选择、希尔、归并、堆、快速,计数,桶,基数)
- 排序算法总结(插入、Shell、选择、堆排序、冒泡、快速、归并、基数)
- python(三)6种排序算法性能比较(冒泡、选择、插入、希尔、快速、归并)
- 基本的排序算法(选择、插入、冒泡、希尔、归并、堆、快速)
- 十种排序算法总结(冒泡、插入、选择、希尔、归并、堆、快速,计数,桶,基数)
- js排序算法总结—冒泡,快速,选择,插入,希尔,归并
- 排序算法Java描述:选择、冒泡、插入、希尔、归并、快速及三向切分快速排序
- 七种排序算法总结(冒泡、插入、选择、希尔、归并、堆、快速)
- 常见内部排序算法 简单数组实现与分析(快速(偶原创partition函数,望众高手指正)、归并、希尔、插入、选择、冒泡)
- js排序算法总结——冒泡,快速,选择,插入,希尔,归并(转载)
- 《冒泡,选择,插入,归并,希尔,快速》排序算法java实现一览
- 十种排序算法总结(冒泡、插入、选择、希尔、归并、堆、快速,计数,桶,基数)
- 十种排序算法总结(冒泡、插入、选择、希尔、归并、堆、快速,计数,桶,基数)