各种排序算法介绍

上传人:suij****uang 文档编号:181877378 上传时间:2023-01-18 格式:DOCX 页数:8 大小:50.96KB
返回 下载 相关 举报
各种排序算法介绍_第1页
第1页 / 共8页
各种排序算法介绍_第2页
第2页 / 共8页
各种排序算法介绍_第3页
第3页 / 共8页
点击查看更多>>
资源描述
快速排序(Quicksort)是对冒泡排序的一种改进。由C.A.R.Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。算法过程设要排序的数组是A0AN-1,首先任意选取一个数据(通常选用第一个数据)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。一趟快速排序的算法是:1)设置两个变量I、J,排序开始的时候:I=0,J=N-1;2)以第一个数组元素作为关键数据,赋值给key,即卩key=A0;3)从J开始向前搜索,即由后开始向前搜索(J=J-1),找到第一个小于key的值AJ,并与AI交换;4)从I开始向后搜索,卩由前开始向后搜索(I=I+1),找到第一个大于key的AI,与AJ交换;5)重复第3、4、5步,直到I=J;(3,4步是在程序中没找到时候j=j-1,i=i+1,直至找到为止。找到并交换的时候i,j指针位置不变。另外当i=j这过程一定正好是i+或j+完成的最后另循环结束)例如:待排序的数组A的值分别是:(初始关键数据:X=49)注意关键X永远不变,永远是和X进行比较,无论在什么位子,最后的目的就是把X放在中间,小的放前面大的放后面。A0、A1、A2、A3、A4、A5、A6:49386597761327进行第一次交换后:27386597761349(按照算法的第三步从后面开始找)进行第二次交换后:27384997761365(按照算法的第四步从前面开始找X的值,6549,两者交换,此时:I=3)进行第三次交换后:27381397764965(按照算法的第五步将又一次执行算法的第三步从后开始找进行第四次交换后:27381349769765(按照算法的第四步从前面开始找大于X的值,9749,两者交换,此时:I=4,J=6)此时再执行第三步的时候就发现I=J,从而结束一趟快速排序,那么经过一趟快速排序之后的结果是:27381349769765,卩所以大于49的数全部在49的后面,所以小于49的数全部在49的前面。快速排序就是递归调用此过程在以49为中点分割这个数据序列,分别对前面一部分和后面一部分进行类似的快速排序,从而完成全部数据序列的快速排序,最后把此数据序列变成一个有序的序列,根据这种思想对于上述数组A的快速排序的全过程如图6所示:初始状态49386597761327进行一次快速排序之后划分为27381349769765分别对前后两部分进行快速排序273813经第三步和第四步交换后变成132738完成排序。769765经第三步和第四步交换后变成657697完成排序。插入排序有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法插入排序法,插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为0(2)。是稳定的排序方法。插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外,而第二部分就只包含这一个元素。在第一部分排序后,再把这个最后元素插入到此刻已是有序的第一部分里的位置插入排序:包括:直接插入排序,二分插入排序(又称折半插入排序),链表插入排序,希尔排序(又称缩小增量排序)。编辑本段基本思想将n个元素的数列分为已有序和无序两个部分,如f插入排序过程示例下所示:,a2,a3,a4,.,anal(l),a2(l),a3(l),a4(l).,an(l)a1(n-1),a2(n-1),.,an(n-1)每次处理就是将无序数列的第一个元素与有序数列的元素从后往前逐个进行比较,找出插入位置,将该元素插入到有序数列的合适位置中。插入排序算法步骤从有序数列和无序数列a2,a3,.,an开始进行排序;处理第i个元素时(i=2,3,.,n),数列al,a2,.,ai-l是已有序的,而数列ai,ai+l,.,an是无序的。用ai与ai-1,ai-2,.,al进行比较,找出合适的位置将ai插入;重复第二步,共进行n-l次插入处理,数列全部有序。voidinsertSort(Type*arr,longlen)/*InsertSortalgorithm*/longi=0,j=0;/*iteratorvalue*/TypetmpData;fl43134爼廉呼(UEk.iL空ID39Rft相耳39b.iil24cmi*甲議厲ismJ24hsksinahs132DJiS?-:assertF(arr!=NULL,InInsertSortsort,arrisNULLn);for(i=l;i0&tmpDataarrj-l)arrj=arrj-l;j-;arrj=tmpData;插入排序算法思路假定这个数组的序是排好的,然后从头往后,如果有数比当前外层元素的值大,则将这个数的位置往后挪,直到当前外层元素的值大于或等于它前面的位置为止.这具算法在排完前k个数之后,可以保证al.k是局部有序的,保证了插入过程的正确性.算法描述一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:1. 从第一个元素开始,该元素可以认为已经被排序2. 取出下一个元素,在已经排序的元素序列中从后向前扫描3. 如果该元素(已排序)大于新元素,将该元素移到下一位置重复步骤3,直到找到已排序的元素小于或者等于新元素的位置将新元素插入到下一位置中重复步骤2如果比较操作的代价比交换操作大的话,可以采用二分杳找法来减少比较操作的数目。该算法可以认为是插入排序的一个变种,称为二分查找排序。C语言示例代码示例代码为C语言,输入参数中,需要排序的数组为array,起始索引为first,终止索引为last。示例代码的函数采用in-place排序,调用完成后,array中从first到last处于升序排列。voidinsertion_sort(chararray,unsignedintfirst,unsignedintlast)inti,j;inttemp;for(i=first+1;i=first)&(arrayjtemp)arrayj+1=arrayj;j-;arrayj+1=temp;这个更好:voidInsertSort(chararray,unsignedintn)inti,j;inttemp;for(i=1;i0&temparrayj-1;j-)/comparethenewarraywithtemparrayj=arrayj-1;/alllargerelementsaremovedonepottotherightarrayj=temp;这个是C+语言版本的插入排序。为了支持list使用了std:advance()。#inCludetemplatevoidinsertion_sort(biIterbegin,biIterend)typedeftypenamestd:iterator_traits:value_typevalue_type;biIterbond=begin;std:advanCe(bond,1);for(;bond!=end;std:advanCe(bond,1)value_typekey=*bond;biIterins=bond;biIterpre=ins;std:advanCe(pre,-1);while(ins!=begin&*prekey)*ins=*pre;std:advanCe(ins,-1);std:advanCe(pre,-1);*ins=key;希尔排序(ShellSort)是插入排序的一种。是针对直接插入排序算法的改进。该方法又称缩小增量排序,因DLShell于1959年提出而得名。基本思想希尔排序基本思想:先取一个小于n的整数di作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2vdl重复上述的分组和排序,直至所取的增量dt=1(dtvdt-ld2dl),即所有记录放在同一组中进行直接插入排序为止。该方法实质上是一种分组插入方法。给定实例的shell排序的排序过程假设待排序文件有10个记录,其关键字分别是:49,38,65,97,76,13,27,49,55,04。增量序列的取值依次为:5,3,1Shell排序Shell排序的算法实现:1不设监视哨的算法描述voidShellPass(SeqListR,intd)/希尔排序中的一趟排序,d为当前增量for(i=d+l;iv=n;i+)将Rd+1.n分别插入各组当前的有序区if(Ri.key0&R0.key0doincrement=increment/3+1;/求下一增量ShellPass(R,increment);/一趟增量为increment的Shell插入排序while(increment1)/ShellSort、,亠-7-.注意:当增量d=1时,ShellPass和InsertSort基本一致,只是由于没有哨兵而在内循环中增加了一个循环判定条件j0,以防下标越界。2.设监视哨的shell排序算法具体算法【参考书目12】算法分析1增量序列的选择Shell排序的执行时间依赖于增量序列。 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。有人通过大量的实验,给出了目前较好的结果:当n较大时,比较和移动的次数约在nAl.25至到1.6*nA1.25之间。2.Shell排序的时间性能优于直接插入排序,据统计分析其时间复杂度为0(1.3)希尔排序的时间性能优于直接插入排序的原因: 当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。 当n值较小时,n和n2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(2)差别不大。 在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。因此,希尔排序在效率上较直接插人排序有较大的改进。3稳定性希尔排序是不稳定的。参见上述实例,该例中两个相同关键字49在排序前后的相对次序发生了变化。交换排序所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。voidswapsort(inta)for(i=0;i9;i+)for(j=i+1;j10;j+)if(aiaj) 好的增量序列的共同特征:最后一个增量必须为1temp=ai;ai=aj;aj=temp;选择排序每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。选择排序是不稳定的排序方法。基本思想n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果:初始状态:无序区为Rl.n,有序区为空。 第l趟排序在无序区R1.n中选出关键字最小的记录Rk,将它与无序区的第1个记录R1交换,使R1.1和R2.n分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。 第i趟排序第i趟排序开始时,当前有序区和无序区分别为R1.i-1和R(1in-1)0该趟排序从当前无序区中选出关键字最小的记录Rk,将它与无序区的第1个记录R交换,使R1.i和R分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。这样,n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果。常见的选择排序细分为简单选择排序、树形选择排序(锦标赛排序)、堆排序。上述算法仅是简单选择排序的步骤。排序过程【示例】:初始关键字4938659776132749第一趟排序后1338659776492749第二趟排序后1327659776493849第三趟排序后1327389776496549第四趟排序后1327384976976549第五趟排序后1327384949976576第六趟排序后1327384949659776第七趟排序后1327384949657697最后排序结果1327384949657697示例代码:#includeusingnamespacestd;intmain()intnum10=9,8,10,3,4,6,4,7,2,1;coutvv排序前:vvendl;for(intm=0;mnumj)pos=j;inttem;tem=numpos;numpos=numi;numi=tem;coutvvendlvv排序后:vvendl;for(intm=0;mv10;m+)coutvvnummvv;return0;二分查找屮L|tfc-taiVRlia卜晝上邑4-.i!a4tor:*L|Bl14严也fl二分查找法二分查找又称折半查找,它是一种效率较高的查找方法。【二分查找要求】:1.必须采用顺序存储结构2.必须按关键字大小有序排列。【优缺点】折半查找法的优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。【算法思想】首先,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。【算法复杂度】假设其数组长度为n,其算法复杂度为o(log(n)下面提供一段二分查找实现的伪代码:BinarySearch(max,min,des)mid-(max+min)/2while(mindesthenmax=mid-1elsemin=mid+1returnmax折半查找法也称为二分查找法,它充分利用了元素间的次序关系,采用分治策略,可在最坏的情况下用O(logn)完成搜索任务。它的基本思想是,将n个元素分成个数大致相同的两半,取an/2与欲查找的x作比较,如果x=an/2则找到x,算法终止。如果xvan/2,则我们只要在数组a的左半部继续搜索x(这里假设数组元素呈升序排列)。如果xan/2,则我们只要在数组a的右半部继续搜索x。堆排序堆积排序(Heapsort)是指利用堆积树(堆)这种资料结构所设计的一种排序算法,可以利用数组的特点快速定位指定索引的元素树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。【例】关键字序列(10,15,56,25,30,70)和(70,56,30,25,15,10)分别满足堆性质(1)和(2),故它们均是堆,其对应的完全二叉树分别如小根堆示例和大根堆示例所示。A/IfiJO7U1IFt.Efl大根堆和小根堆:根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最小者的堆称为小根堆,又称最小堆。根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大根堆,又称最大堆。注意:堆中任一子树亦是堆。以上讨论的堆实际上是二叉堆(BinaryHeap),类似地可定义k叉堆。堆的高度堆可以被看成是一棵树,结点在堆中的高度可以被定义为从本结点到叶子结点的最长简单下降路径上边的数目;定义堆的高度为树根的高度。我们将看到,堆结构上的一些基本操作的运行时间至多是与树的高度成正比,为O(lgn)。堆排序堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。(1)用大根堆排序的基本思想 先将初始文件Rl.n建成一个大根堆,此堆为初始的无序区 再将关键字最大的记录R1(即堆顶)和无序区的最后一个记录Rn交换,由此得到新的无序区R1.n-1和有序区Rn,且满足R1.n-l.keys0Rn.key 由于交换后新的根R1可能违反堆性质,故应将当前无序区R1.n-1调整为堆。然后再次将R1.n-1中关键字最大的记录R1和该区间的最后一个记录Rn-1交换,由此得到新的无序区R1.n-2和有序区Rn-1.n,且仍满足关系R1.n-2.keys0Rn-1.n.keys,同样要将R1.n-2调整为堆。直到无序区只有一个元素为止。(2)大根堆排序算法的基本操作: 初始化操作:将R1.n构造为初始堆; 每一趟排序的基本操作:将当前无序区的堆顶记录R1和该区间的最后一个记录交换,然后将新的无序区调整为堆(亦称重建堆)。注意: 只需做n-1趟排序,选出较大的n-1个关键字即可以使得文件递增有序。用小根堆排序与利用大根堆类似,只不过其排序结果是递减有序的。堆排序和直接选择排序相反:在任何时刻堆排序中无序区总是在有序区之前,且有序区是在原向量的尾部由后往前逐步扩大至整个向量为止特点堆排序(HeapSort)是一树形选择排序。堆排序的特点是:在排序过程中,将Rl.n看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系(参见二叉树的顺序存储结构),在当前无序区中选择关键字最大(或最小)的记录堆排序与直接选择排序的区别直接选择排序中,为了从R1.n中选出关键字最小的记录,必须进行n-1次比较,然后在R2.n中选出关键字最小的记录,又需要做n-2次比较。事实上,后面的n-2次比较中,有许多比较可能在前面的n-1次比较中已经做过,但由于前一趟排序时未保留这些比较结果,所以后一趟排序时又重复执行了这些比较操作。堆排序可通过树形结构保存部分比较结果,可减少比较次数。算法分析堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销构成,它们均是通过调用Heapify实现的。堆排序的最坏时间复杂度为O(nlog2n)。堆序的平均性能较接近于最坏性能。由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。堆排序是就地排序,辅助空间为0(1),它是不稳定的排序方法。#defineMAX100/数据元素的最大个数typedefstructintrMAX;intlength;SqList;定义一个线性表用于存放数据元素voidHeapAdjust(SqList&L,ints,intm)/已知L.rs.m中记录除L.rs外均满足堆的定义,本函数用于使L.rs.m成为一个大顶堆intj;inte=L.rs;for(j=2*s;j=m;j*=2)if(jM&L.RJ=L.rj)break;L.rs=L.rj;s=j;L.rs=e;voidHeapSort(SqList&L)/对顺序表L进行堆排序inti,e;for(i=L.length/2;i0;i-)HeapAdjust(L,i,L.length);for(i=L.length;i1;i-)/将大顶堆的顶记录和最后一个记录相互交换e=L.r1;L.r1=L.ri;L.ri=e;HeapAdjust(L,1,i-1);归并排序归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(DivideandConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。如设有数列6,202,100,301,38,8,1初始状态:62021003013881比较次数i=1620210030183813i=2610020230118384i=3168381002023014总计:11次归并操作的工作原理如下:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列设定两个指针,最初位置分别为两个已经排序序列的起始位置比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置重复步骤3直到某一指针达到序列尾将另一序列剩下的所有元素直接复制到合并序列尾示例代码为C语言,输入参数中,需要排序的数组为array,起始索引为first,终止索引为last。调用完成后,array中从first到last处于升序排列。voidMergeSort(intarray,intfirst,intlast)intmid=0;if(firstlast)mid=(first+last)/2;MergeSort(array,first,mid);MergeSort(array,mid+1,last);Merge(array,first,mid,last);
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 解决方案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!