八大排序算法
【IT专家】精通八大排序算法系列:一、快速排序算法

精通八大排序算法系列:一、快速排序算法2011/01/09 583 写此八大排序算法系列之前,先说点题外话。
每写一篇文章,我都会遵循以下几点原则:一、保持版面的尽量清晰,力保排版良好。
二、力争所写的东西,清晰易懂,图文并茂三、尽最大可能确保所写的东西精准,有实用价值。
因为,我觉得,你既然要把你的文章,公布出来,那么你就一定要为你的读者负责。
不然,就不要发表出来。
一切,为读者服务。
ok,闲不多说。
接下来,咱们立刻进入本文章的主题,排序算法。
众所周知,快速排序算法是排序算法中的重头戏。
因此,本系列,本文就从快速排序开始。
------------------------------------------------------ 一、快速排序算法的基本特性时间复杂度:O(n*lgn)最坏:O(n )空间复杂度:O(n*lgn)不稳定。
快速排序是一种排序算法,对包含n个数的输入数组,平均时间为O(nlgn),最坏情况是O(n )。
通常是用于排序的最佳选择。
因为,排序最快,也只能达到O (nlgn)。
二、快速排序算法的描述算法导论,第7章快速排序时基于分治模式处理的,对一个典型子数组A[p...r]排序的分治过程为三个步骤:1.分解:A[p..r]被划分为俩个(可能空)的子数组A[p ..q-1]和A[q+1 ..r],使得A[p ..q-1] = A[q] = A[q+1 ..r]2.解决:通过递归调用快速排序,对子数组A[p ..q-1]和A[q+1 ..r]排序。
3.合并。
三、快速排序算法 版本一:QUICKSORT(A, p, r)1 if p r2 then q ←PARTITION(A, p, r) //关键3 QUICKSORT(A, p, q - 1)4 QUICKSORT(A, q + 1, r) 数组划分快速排序算法的关键是PARTITION过程,它对A[p..r]进行就地重排:PARTITION(A, p, r)1 x ← A[r]2 i ← p - 13 for j ← p to r - 14 do if A[j] ≤ x5 then i ← i + 16 exchange A[i] - A[j]7 exchange A[i + 1] - A[r]8 return i + 1。
十大经典排序算法总结

⼗⼤经典排序算法总结最近⼏天在研究算法,将⼏种排序算法整理了⼀下,便于对这些排序算法进⾏⽐较,若有错误的地⽅,还请⼤家指正0、排序算法说明0.1 排序术语稳定:如果a=b,且a原本排在b前⾯,排序之后a仍排在b的前⾯不稳定:如果a=b,且a原本排在b前⾯,排序之后排在b的后⾯时间复杂度:⼀个算法执⾏所耗费的时间空间复杂度:⼀个算法执⾏完所需内存的⼤⼩内排序:所有排序操作都在内存中完成外排序:由于数据太⼤,因此把数据放在磁盘中,⽽排序通过磁盘和内存的数据传输才能进⾏0.2算法时间复杂度、空间复杂度⽐较0.3名词解释n:数据规模k:桶的个数In-place:占⽤常数内存,不占⽤额外内存Out-place:占⽤额外内存0.4算法分类1.冒泡排序冒泡排序是⼀种简单的排序算法。
它重复地⾛访过要排序的数列,⼀次⽐较两个元素,如果它们的顺序错误就把它们交换过来。
⾛访数列的⼯作是重复地进⾏直到没有再需要交换,也就是说该数列已经排序完成。
这个算法的名字由来是因为越⼩的元素会经由交换慢慢“浮”到数列的顶端1.1算法描述⽐较相邻的元素,如果前⼀个⽐后⼀个打,就交换对每⼀对相邻元素做同样的⼯作,从开始第⼀对到结尾最后⼀对,这样在最后的元素应该会是最⼤的数针对所有的元素重复以上的步骤,除了最后⼀个重复步骤1-3,知道排序完成1.2动图演⽰1.3代码实现public static int[] bubbleSort(int[] array) {if (array.length == 0)return array;for (int i = 0; i < array.length; i++)for (int j = 0; j < array.length - 1 - i; j++)if (array[j + 1] < array[j]) {int temp = array[j + 1];array[j + 1] = array[j];array[j] = temp;}return array;}1.4算法分析最佳情况:T(n) = O(n) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(n2)2.选择排序表现简单直观的最稳定的排序算法之⼀,因为⽆论什么数据都是O(n2)的时间复杂度,⾸先在未排序序列中找到最⼩(⼤)元素,与数组中第⼀个元素交换位置,作为排序序列的起始位置,然后再从剩余未排序元素中继续寻找最⼩(⼤)的元素,与数组中的下⼀个元素交换位置,也就是放在已排序序列的末尾2.1算法描述1.初始状态:⽆序区为R[1..n],有序区为空2.第i躺排序开始时,当前有序区和⽆序区R[1..i-1]、R[i..n]3.n-1趟结束,数组有序化2.2动图演⽰2.3代码实现public static int[] selectionSort(int[] array) {if (array.length == 0)return array;for (int i = 0; i < array.length; i++) {int minIndex = i;for (int j = i; j < array.length; j++) {if (array[j] < array[minIndex]) //找到最⼩的数minIndex = j; //将最⼩数的索引保存}int temp = array[minIndex];array[minIndex] = array[i];array[i] = temp;}return array;}2.4算法分析最佳情况:T(n) = O(n2) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(n2)3、插⼊排序是⼀种简单直观的排序算法,通过构建有序序列,对于未排序序列,在已排序序列中从后向前扫描,找到相应位置并插⼊,需要反复把已排序元素逐步向后挪位,为最新元素腾出插⼊空间3.1算法描述1.从第⼀个元素开始,该元素可以认为已经被排序2.取出下⼀个元素(h),在已排序的元素序列中从后往前扫描3.如果当前元素⼤于h,将当前元素移到下⼀位置4.重复步骤3,直到找到已排序的元素⼩于等于h的位置5.将h插⼊到该位置6.重复步骤2-53.2动图演⽰3.3代码实现public static int[] insertionSort(int[] array) {if (array.length == 0)return array;int current;for (int i = 0; i < array.length - 1; i++) {current = array[i + 1];int preIndex = i;while (preIndex >= 0 && current < array[preIndex]) {array[preIndex + 1] = array[preIndex];preIndex--;}array[preIndex + 1] = current;}return array;}3.4算法分析最佳情况:T(n) = O(n) 最坏情况:T(n) = O(n2) 平均情况:T(n) = O(n2)4、希尔排序是简单插⼊排序经过改进之后的⼀个更⾼效的版本,也称为缩⼩增量排序,同时该算法是冲破O(n2)的第⼀批算法之⼀。
十大排序算法原理

十大排序算法原理排序算法是计算机科学中最基本的算法之一,它可以将一组无序的数据按照一定的规则进行排列,使得数据更加有序,方便后续的处理。
在计算机科学中,有许多种排序算法,其中比较经典的有十大排序算法,它们分别是冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序、桶排序和基数排序。
1. 冒泡排序冒泡排序是一种简单的排序算法,它的基本思想是从头到尾依次比较相邻的两个元素,如果前一个元素比后一个元素大,则交换它们的位置。
这样一趟下来,最大的元素就被排到了最后面。
然后再对剩下的元素进行同样的操作,直到所有元素都被排好序为止。
2. 选择排序选择排序是一种简单的排序算法,它的基本思想是从待排序的数据中选择最小的元素,将其放到已排序的数据的末尾。
然后再从剩余的数据中选择最小的元素,放到已排序的数据的末尾。
依次类推,直到所有的数据都被排序完毕。
3. 插入排序插入排序是一种简单的排序算法,它的基本思想是将待排序的数据分为已排序和未排序两部分,每次从未排序的数据中取出一个元素,插入到已排序的数据中的合适位置。
插入的过程中,需要将已排序的数据中比插入元素大的元素向后移动一位,为插入元素腾出位置。
4. 希尔排序希尔排序是一种改进的插入排序算法,它的基本思想是将待排序的数据分成若干个子序列,对每个子序列进行插入排序,然后再将所有子序列合并成一个序列。
希尔排序的特点是可以先对距离较远的元素进行比较和交换,从而减少比较和交换的次数,提高排序的效率。
5. 归并排序归并排序是一种分治算法,它的基本思想是将待排序的数据分成两个子序列,对每个子序列进行排序,然后将两个子序列合并成一个有序序列。
归并排序的特点是稳定、效率高,但需要额外的存储空间。
6. 快速排序快速排序是一种分治算法,它的基本思想是选择一个基准元素,将待排序的数据分成两个子序列,一个子序列中的元素都比基准元素小,另一个子序列中的元素都比基准元素大。
深入浅出-C语言8种经典排序算法

for(i=0;i<n-j;i++) /* 值比较大的元素沉下去后,只把剩下的元素中的最大值再 沉下去就可以啦 */
{ if(a[i]>a[i+1]) /* 把值比较大的元素沉到底 */ { k=a[i]; a[i]=a[i+1]; a[i+1]=k; }
(8)堆排序 我们知道堆的结构是节点 i 的孩子为 2*i 和 2*i+1 节点,大顶堆要求父节点大于等于其 2 个 子节点,小顶堆要求父节点小于等于其 2 个子节点。在一个长为 n 的序列,堆排序的过程是 从第 n/2 开始和其子节点共 3 个值选择最大(大顶堆)或者最小(小顶堆),这 3 个元素之间的选 择当然不会破坏稳定性。但当为 n/2-1, n/2-2, ...1 这些个父节点选择元素时,就会破坏稳定性。 有可能第 n/2 个父节点交换把后面一个元素交换过去了,而第 n/2-1 个父节点把后面一个相 同的元素没有交换,那么这 2 个相同的元素之间的稳定性就被破坏了。所以,堆排序不是稳 定的排序算法.
input[j + 1] = input[j]; /* 一边找一边移动元素 */ input[j] = temp; } } }
5.折半插入排序
5
折半插入排序算法是一种稳定的排序算法,比直接插入算法明显减少了关键字之间比较的次
程思想,值得学习
void sort(int num[], int low, int high) {
int i;
while(low<high) {
for(i=low; i<high; i++) /* bubble to high */ if(num[i]>num[i+1]) swap(num[i], num[i+1]);
算法_八大排序算法总结

算法_⼋⼤排序算法总结最近笔试⾯试中经常考到排序算法,及其对应的时间复杂度和空间复杂度分析,现做如下总结。
⼀,冒泡排序思想:对于0~n-1,依次⽐较相邻两个数,前者⽐后者⼤就交换,⼀轮后A[n-1]是最⼤数,在对0~n-2执⾏以上步骤,则A[n-2]是第⼆⼤的数,循环执⾏上⾯的步骤即可,形象的可以理解为⼤的数⼀个个冒到后⾯去,所以叫冒泡排序。
⽰意图:⾸先6和3⽐较,6⽐3⼤,交换6和5⽐较,交换6和7⽐较,不⽤交换依次执⾏以上步骤,第⼀轮后,序列变为接着,在0到n-2上执⾏以上步骤⼀轮过后,则变为依次执⾏以上步骤,最后序列为时间复杂度: O(n^2)空间复杂度:O(1)代码:1class BubbleSort {2public:3int* bubbleSort(int* A, int n)4 {5int temp;6// write code here7for(int i = 0; i < n; i++)8 {9for(int j = 0; j < n - i - 1; j++)10 {11if(A[j] > A[j+1])12 {13 temp = A[j];14 A[j] = A[j + 1];15 A[j + 1] = temp;16 }17 }1819 }20return A;21 }22 };⼆,选择排序思想:在序列中依次选择最⼩值放到最前端,重复以上步骤,只到排序完成⽰意图:最⼩数为0,放到最前端1到n-1最⼩数为1,放到最前端依次执⾏以上步骤,最后为时间复杂度:O(n^2)空间复杂度:O(1)代码:1class SelectionSort {2public:3int* selectionSort(int* A, int n)4 {5// write code here6//从前往后依次放⼊为排序的数组的最⼩值7int min_b;8int temp;9for(int i = 0; i < n - 1; i++)10 {11 min_b = i;12for(int j = i; j < n; j++) //寻找最⼩值13 {14if(A[min_b] > A[j])15 min_b = j;1617 }18 temp = A[i];19 A[i] = A[min_b];20 A[min_b] = temp;21 }22return A;23 }24 };三,插⼊排序思想:对于数组A[n],保证前⾯的A[0]~A[m]是排序好的,再把A[m+1]插⼊到前⾯排好序的序列中,m递增,知道m=n-2⽰意图:原始序列为:6和5⽐较,6⽐5⼤,要交换接下来把3插⼊到前⾯排好序的序列中,⾸先3和6⽐,6⼤,后移⼀位接着3和5⽐较,5⼤,后移⼀位只到前⾯没有数了,或者前⾯的数⽐要插⼊的数⼩,就在对应的位置插⼊该数再对1执⾏以上步骤重复以上步骤,只到整个序列排序完成时间复杂度:O(n^2)空间复杂度:O(1)代码1class InsertionSort {2public:3int* insertionSort(int* A, int n)4 {5// write code here6int temp;7for(int i = 1; i < n; i ++)8 {9 temp = A[i];10for(int j = i - 1; j >= 0; j--)11 {12if(temp < A[j])13 {14 A[j + 1] = A[j];15if(j == 0)16 {17 A[j] = temp;18 }19 }20else21 {22 A[j + 1] = temp;23break;24 }25 }26 }27return A;28 }29 };四,归并排序思想:对数组中每个数看成是长度为1的有序区间,接着合并相邻两个长度为1的有序区间,变为长度为2的有序区间,接着合并相邻长度为2的有序区间变成长度为4的有序区间,依次进⾏,只到排序完成⽰意图:⾸先为长度为1的有序区间合并为长度为2的有序区间合并为长度为4的有序区间合并为长度为8的有序区间,排序完成时间复杂度:O(nlogn)空间复杂度:O(N)代码1class MergeSort {2public:3int* mergeSort(int* A, int n)4 {5 mergeSort(A,0,n-1);6return A;78 }9void mergeSort(int* A, int left, int right)10 {11if(left == right)12return;13int mid=(left+right)/2;14 mergeSort(A,left,mid);15 mergeSort(A,mid+1,right);16 merge_p(A,left,mid,right);17return;18 }1920void merge_p(int* A, int left, int mid, int right)21 {22int* temp = new int[right - left + 1];23int l = left;24int r = mid + 1;25int k = 0;26while(l <= mid && r <= right)27 {28if(A[l] < A[r])29 temp[k++] = A[l++];30else31 temp[k++] = A[r++];32 }33while(l <= mid)34 temp[k++] = A[l++];35while(r <= right)36 temp[k++] = A[r++];37for(int i = 0; i < k; i++)38 {39 A[left + i] = temp[i];40 }41 }4243 };五,快速排序思想:随机选择数组中的数,⼩于等于这个数的放在左边,⼤于这个数的放在右边,递归调⽤以上步骤,完成排序⽰意图:⾸先随机选择,划分区间递归调⽤,即可完成排序。
八种基本排序及其空间复杂度

八种基本排序及其空间复杂度排序,听起来就像是让东西乖乖排队一样,没错,这就是它的意思!在这个信息爆炸的时代,数据多得让人眼花缭乱,排序就是让我们把这些数据变得整齐划一的好帮手。
今天,我们来聊聊八种基本的排序方法,当然也顺便说说它们的空间复杂度,别担心,我会尽量让这段旅程轻松愉快,保证你听了不打瞌睡。
冒泡排序,名字听起来是不是很萌?就像泡泡一样,慢慢浮上来。
它的原理简单得令人发笑,两两比较,把较大的“泡泡”往后推,简直像是在给小朋友们上课,让他们学会乖乖排队。
可这家伙慢得要命,特别是在数据量大的时候,简直像是乌龟赛跑,空间复杂度只有O(1),真是个勤俭节约的小家伙。
再来就是选择排序,顾名思义,它喜欢选择最小的那个,然后把它放到前面。
就像逛超市时,你每次都挑最便宜的商品,心里想着“哎呀,这个买了肯定划算!”但是,这货也慢得让人抓狂,时间复杂度是O(n^2),但是空间复杂度还是O(1),让我们知道选择固然重要,但速度更重要啊!插入排序就像是老派的舞会,大家一个个走上舞台,找到自己的位置。
刚开始,可能有点笨拙,但一旦上手,嘿,效率可高了。
尤其是在小数据量的时候,简直就像刀切黄油,流畅得不得了。
它的空间复杂度同样是O(1),这小子真是能省就是能省,值得点赞!然后,我们得聊聊快速排序,这个家伙可不简单。
它聪明地选择一个“基准”,然后把比它小的放一边,大的放另一边,瞬间就像变魔术一样。
时间复杂度在平均情况下是O(n log n),空间复杂度是O(log n),哎呀,这小子真的是神乎其神,仿佛在说:“看,我多聪明!”再说说归并排序,这是一种比较优雅的排序方式,仿佛优雅的绅士走入舞会。
他先把数据分成小块,然后再慢慢合并,像拼图一样,最终把完整的画面呈现出来。
时间复杂度同样是O(n log n),但是它的空间复杂度可是O(n),得花费点空间来存放那些临时的数据。
然后有个小家伙叫希尔排序,这名字听上去有点高深,其实就是插入排序的升级版。
8大排序算法

排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。
我们这里说说八大排序就是内部排序。
当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序、堆排序或归并排序序。
快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;基本思想:将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表。
即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。
要点:设立哨兵,作为临时存储和判断数组边界之用。
直接插入排序示例:如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。
所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
算法的实现:1.void print(int a[], int n ,int i){2. cout<<i <<":";3.for(int j= 0; j<8; j++){4. cout<<a[j] <<" ";5. }6. cout<<endl;7.}8.9.10.void InsertSort(int a[], int n)11.{12.for(int i= 1; i<n; i++){13.if(a[i] < a[i-1]){ //若第i个元素大于i-1元素,直接插入。
小于的话,移动有序表后插入14.int j= i-1;15.int x = a[i]; //复制为哨兵,即存储待排序元素16. a[i] = a[i-1]; //先后移一个元素17.while(x < a[j]){ //查找在有序表的插入位置18. a[j+1] = a[j];19. j--; //元素后移20. }21. a[j+1] = x; //插入到正确位置22. }23. print(a,n,i); //打印每趟排序的结果24. }25.26.}27.28.int main(){29.int a[8] = {3,1,5,7,2,4,9,6};30. InsertSort(a,8);31. print(a,8,8);32.}效率:时间复杂度:O(n^2).其他的插入排序有二分插入排序,2-路插入排序。
十大经典排序算法(动图演示)

⼗⼤经典排序算法(动图演⽰)0、算法概述0.1 算法分类⼗种常见排序算法可以分为两⼤类:⽐较类排序:通过⽐较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为⾮线性时间⽐较类排序。
⾮⽐较类排序:不通过⽐较来决定元素间的相对次序,它可以突破基于⽐较排序的时间下界,以线性时间运⾏,因此也称为线性时间⾮⽐较类排序。
0.2 算法复杂度0.3 相关概念稳定:如果a原本在b前⾯,⽽a=b,排序之后a仍然在b的前⾯。
不稳定:如果a原本在b的前⾯,⽽a=b,排序之后 a 可能会出现在 b 的后⾯。
时间复杂度:对排序数据的总的操作次数。
反映当n变化时,操作次数呈现什么规律。
空间复杂度:是指算法在计算机内执⾏时所需存储空间的度量,它也是数据规模n的函数。
1、冒泡排序(Bubble Sort)冒泡排序是⼀种简单的排序算法。
它重复地⾛访过要排序的数列,⼀次⽐较两个元素,如果它们的顺序错误就把它们交换过来。
⾛访数列的⼯作是重复地进⾏直到没有再需要交换,也就是说该数列已经排序完成。
这个算法的名字由来是因为越⼩的元素会经由交换慢慢“浮”到数列的顶端。
1.1 算法描述⽐较相邻的元素。
如果第⼀个⽐第⼆个⼤,就交换它们两个;对每⼀对相邻元素作同样的⼯作,从开始第⼀对到结尾的最后⼀对,这样在最后的元素应该会是最⼤的数;针对所有的元素重复以上的步骤,除了最后⼀个;重复步骤1~3,直到排序完成。
1.2 动图演⽰1.3 代码实现function bubbleSort(arr) {var len = arr.length;for (var i = 0; i < len - 1; i++) {for (var j = 0; j < len - 1 - i; j++) {if (arr[j] > arr[j+1]) { // 相邻元素两两对⽐var temp = arr[j+1]; // 元素交换arr[j+1] = arr[j];arr[j] = temp;}}}return arr;}2、选择排序(Selection Sort)选择排序(Selection-sort)是⼀种简单直观的排序算法。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
八大排序算法排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。
我们这里说说八大排序就是内部排序。
当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序、堆排序或归并排序序。
快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;基本思想:将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表。
即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。
要点:设立哨兵,作为临时存储和判断数组边界之用。
直接插入排序示例:如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。
所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
算法的实现:[cpp]view plaincopyprint?1.void print(int a[], int n ,int i){2. cout<<i <<":";3.for(int j= 0; j<8; j++){4. cout<<a[j] <<" ";5. }6. cout<<endl;7.}8.9.10.void InsertSort(int a[], int n)11.{12.for(int i= 1; i<n; i++){13.if(a[i] < a[i-1]){ //若第i个元素大于i-1元素,直接插入。
小于的话,移动有序表后插入14.int j= i-1;15.int x = a[i]; //复制为哨兵,即存储待排序元素16. a[i] = a[i-1]; //先后移一个元素17.while(x < a[j]){ //查找在有序表的插入位置18. a[j+1] = a[j];19. j--; //元素后移20. }21. a[j+1] = x; //插入到正确位置22. }23. print(a,n,i); //打印每趟排序的结果24. }25.26.}27.28.int main(){29.int a[8] = {3,1,5,7,2,4,9,6};30. InsertSort(a,8);31. print(a,8,8);32.}效率:时间复杂度:O(n^2).其他的插入排序有二分插入排序,2-路插入排序。
希尔排序是1959 年由D.L.Shell 提出来的,相对直接排序有较大的改进。
希尔排序又叫缩小增量排序基本思想:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
操作方法:1. 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;2. 按增量序列个数k,对序列进行k 趟排序;3. 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。
仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
希尔排序的示例:算法实现:我们简单处理增量序列:增量序列d = {n/2 ,n/4, n/8 .....1} n为要排序数的个数即:先将要排序的一组记录按某个增量d(n/2,n为要排序数的个数)分成若干组子序列,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。
继续不断缩小增量直至为1,最后使用直接插入排序完成排序。
[cpp]view plaincopyprint?1.void print(int a[], int n ,int i){2. cout<<i <<":";3.for(int j= 0; j<8; j++){4. cout<<a[j] <<" ";5. }6. cout<<endl;7.}8./**9. * 直接插入排序的一般形式10. *11. * @param int dk 缩小增量,如果是直接插入排序,dk=112. *13. */14.15.void ShellInsertSort(int a[], int n, int dk)16.{17.for(int i= dk; i<n; ++i){18.if(a[i] < a[i-dk]){ //若第i个元素大于i-1元素,直接插入。
小于的话,移动有序表后插入19.int j = i-dk;20.int x = a[i]; //复制为哨兵,即存储待排序元素21. a[i] = a[i-dk]; //首先后移一个元素22.while(x < a[j]){ //查找在有序表的插入位置23. a[j+dk] = a[j];24. j -= dk; //元素后移25. }26. a[j+dk] = x; //插入到正确位置27. }28. print(a, n,i );29. }30.31.}32.33./**34. * 先按增量d(n/2,n为要排序数的个数进行希尔排序35. *36. */37.void shellSort(int a[], int n){38.39.int dk = n/2;40.while( dk >= 1 ){41. ShellInsertSort(a, n, dk);42. dk = dk/2;43. }44.}45.int main(){46.int a[8] = {3,1,5,7,2,4,9,6};47.//ShellInsertSort(a,8,1); //直接插入排序48. shellSort(a,8); //希尔插入排序49. print(a,8,8);50.}希尔排序时效分析很难,关键码的比较次数与记录移动次数依赖于增量因子序列d的选取,特定情况下可以准确估算出关键码的比较次数和记录的移动次数。
目前还没有人给出选取最好的增量因子序列的方法。
增量因子序列可以有各种取法,有取奇数的,也有取质数的,但需要注意:增量因子中除1 外没有公因子,且最后一个增量因子必须为1。
希尔排序方法是一个不稳定的排序方法。
基本思想:在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换;然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素(最后一个数)比较为止。
简单选择排序的示例:操作方法:第一趟,从n 个记录中找出关键码最小的记录与第一个记录交换;第二趟,从第二个记录开始的n-1 个记录中再选出关键码最小的记录与第二个记录交换;以此类推.....第i 趟,则从第i 个记录开始的n-i+1 个记录中选出关键码最小的记录与第i 个记录交换,直到整个序列按关键码有序。
算法实现:[cpp]view plaincopyprint?1.void print(int a[], int n ,int i){2. cout<<"第"<<i+1 <<"趟 : ";3.for(int j= 0; j<8; j++){4. cout<<a[j] <<" ";5. }6. cout<<endl;7.}8./**9. * 数组的最小值10. *11. * @return int 数组的键值12. */13.int SelectMinKey(int a[], int n, int i)14.{15.int k = i;16.for(int j=i+1 ;j< n; ++j) {17.if(a[k] > a[j]) k = j;18. }19.return k;20.}21.22./**23. * 选择排序24. *25. */26.void selectSort(int a[], int n){27.int key, tmp;28.for(int i = 0; i< n; ++i) {29. key = SelectMinKey(a, n,i); //选择最小的元素30.if(key != i){31. tmp = a[i]; a[i] = a[key]; a[key] = tmp; //最小元素与第i位置元素互换32. }33. print(a, n , i);34. }35.}36.int main(){37.int a[8] = {3,1,5,7,2,4,9,6};38. cout<<"初始值:";39.for(int j= 0; j<8; j++){40. cout<<a[j] <<" ";41. }42. cout<<endl<<endl;43. selectSort(a, 8);44. print(a,8,8);45.}简单选择排序的改进——二元选择排序简单选择排序,每趟循环只能确定一个元素排序后的定位。
我们可以考虑改进为每趟循环确定两个元素(当前趟最大和最小记录)的位置,从而减少排序所需的循环次数。
改进后对n 个数据进行排序,最多只需进行[n/2]趟循环即可。
具体实现如下:[cpp]view plaincopyprint?1.void SelectSort(int r[],int n) {2.int i ,j , min ,max, tmp;3.for (i=1 ;i <= n/2;i++) {4.// 做不超过n/2趟选择排序5. min = i; max = i ; //分别记录最大和最小关键字记录位置6.for (j= i+1; j<= n-i; j++) {7.if (r[j] > r[max]) {8. max = j ; continue ;9. }10.if (r[j]< r[min]) {11. min = j ;12. }13. }14.//该交换操作还可分情况讨论以提高效率15. tmp = r[i-1]; r[i-1] = r[min]; r[min] = tmp;16. tmp = r[n-i]; r[n-i] = r[max]; r[max] = tmp;17.18. }19.}堆排序是一种树形选择排序,是对直接选择排序的有效改进。