数据结构之快速排序

来源:互联网 发布:希尔伯特曲线算法 编辑:程序博客网 时间:2024/05/29 09:56

               

              小目录

             1.冒泡排序

             2.快速排序

                

          1.冒泡排序

          冒泡排序我想可能是学习C语言接触的第一个排序算法了,相信每一本C语言的数组的章节都会介绍这个排序算法的。下面我们就从一个类冒泡排序算法来一步步优化这个算法。

          冒泡排序的基本思想:它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

         下面给出一个类冒泡排序的程序,注意这不是冒泡排序,但其过程是有冒泡排序的特点的。

/** @description:类冒泡排序*/void BubbleSort_1(SqList *L) {int i,j;//注意这里没有等于for(i = 1; i < (*L).length ; i++) {for(j = i + 1; j <= (*L).length; j++)if((*L).r[i].key > (*L).r[j].key) swap(L,i,j);}}
      

     这里给出调用到的swap函数,后面不会再提示:

/** @description:用于交换要节点元素位置*/void swap(SqList *L,int i,int j) {ElemType temp;temp = (*L).r[i];(*L).r[i] = (*L).r[j];(*L).r[j] = temp;}
           

        可以看到这里并不是相邻两个元素的比较交换,接下来我们来看看常见的冒泡排序算法:

/** @description:冒泡排序,相邻两元素比较* @more:这个相对于上面的优化在于冒泡在冒泡的过程也把相关的元素的位置上升了*/void BubbleSort_2(SqList *L) {int i,j;for(i = 1; i < (*L).length ; i++) {for(j = (*L).length - 1; j >= i; j-- )//注意这里的不同if((*L).r[j].key > (*L).r[j + 1].key)swap(L,j + 1,j);}}

                                                                                                                     


              从两个程序可以看出来,冒泡在比较的过程中不仅仅把最小的(或者最大的元素)往上冒泡了,还把相关的元素的也往上冒泡了,这样在无形中就减少下一次的移动次数。

        性能分析:若是反序的,需要进行

趟排序。每趟排序要进行
次关键字的比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:
  

冒泡排序的最坏时间复杂度为
。综上,因此冒泡排序总的平均时间复杂度为
,空间复杂度为O(n)。冒泡排序是稳定的排序算法,因为在相邻两元素比较时只有小于或是大于才交换

           改进冒泡排序:
           再次感受到感受到前人的牛逼,但是有点优化的规律是这样的:要充分利用前面已经进行的比较来减少当前所需进行的比较(还记得KMP算法吗)。这里所谓的改进的冒泡算法就是当待排序列部分有序时,比如 序列2 ,1,3,4,5,6在调整一次后为1,2,3,4,5,6这时候如果还按照上面的冒泡算法还需要进行后面的比较,这不是浪费吗!比如,现在再次进行调整(注意这里从后面扫描),则发现一路往上都没有需要交换的,这是不是代表着有序了,如果存在无序必然存在交换,于是我们想到用一个标志来记录是否发生了交换。实现程序如下:
/** @description:优化之后的冒泡排序* @more:这是顺序比较的,在部分有序的情况下体现效果在最坏的情况下和上面的冒泡排序是一样的*/void BubbleSort_3(SqList *L) {int i,j,flag;flag = 1;for(i = 1; i < (*L).length && flag; i++) {flag = 0;for(j = (*L).length - 1; j >= i; j--)  {if((*L).r[j].key > (*L).r[j + 1].key) {swap(L,j + 1,j);flag = 1;}}}}
     性能分析:优化后的算法只是在序列部分有序时才体现效果,其时间复杂度依然是O(n的平方),为稳定排序算法。

     
       2.快速排序
       快速排序是对冒泡的一种改进,它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

/** @descrption:快速排序具体交换操作,函数最后返回最后的基准的位置* @more:基本思想:设置一个基准,从high一直往前找,找到第一个比基准值小,交换他们两;接着从low一直往后找,找到第一个比基准大的,交换他们两这里的基准预设为的第一个元素*/int Partition(SqList *L,int low,int high) {KeyType pivkey;//使用第0个空位来暂存基准值(*L).r[0] = (*L).r[low];pivkey = (*L).r[low].key;//用当前的顺序表的第一个元素关键词作为基准值while(low < high) {//一直往前找while(low < high && (*L).r[high].key >= pivkey) high--;//找到直接复制(*L).r[low] = (*L).r[high];//一直往后找while(low < high && (*L).r[low].key < pivkey) low++;(*L).r[high] = (*L).r[low];}(*L).r[low] = (*L).r[0];return low;}/** @description:递归排序*/void QSort(SqList *L,int low,int high) {int pivloc;if(low < high) {pivloc = Partition(L,low,high);QSort(L,low,pivloc - 1);QSort(L,pivloc + 1,high);}}/** @description:快速排序* @more:快速排序是目前认为最好的一种内部排序方法*/void QuickSort(SqList *L) {QSort(L,1,(*L).length);}
         可以看出来算法设置一个基准,从high一直往前找,找到第一个比基准值小,交换他们两;接着从low一直往后找,找到第一个比基准大的,交换他们两
    这里的基准预设为的第一个元素

        
     csdn这玩意不知道怎么了,老是自动给图片加水印把内容挡住了,以后再补图吧。
     性能分析:快速排序的最坏情况下的时间复杂度为O(n的平方)但是其平均时间复杂度为O(nlogn),这是前面介绍的冒泡和插入排序所不具备的。所以快速排序被认为是目前性能最好的内部排序算法。该排序算法为不稳定排序算法。

    最后附上源码地址:GitHub



0 0
原创粉丝点击