zoukankan      html  css  js  c++  java
  • 快速排序(改进的冒泡排序)

      快速排序的基本思想:从记录中选定一个关键字,将待排序记录分割成两部分,其中一部分记录的关键字小于选定关键字的值,另一部分记录的关键字大于选定关键字的值;反复对分割好的记录进行上述操作,直到整个序列变为有序序列。

      以顺序表L = {0,5,1,9,8,3}为例,length = 5,r[0]不参与排序。

      快速排序的代码如下所示:

     1 //交换顺序表L中的记录,使枢轴记录放到正确位置,并返回其所在位置
     2 //交换结束后,枢轴记录前面的记录值小于枢轴记录的值
     3 //后面的记录值大于枢轴记录的值
     4 int Partition(SqList* L, int low, int high)
     5 {
     6     int pivotkey;
     7     pivotkey = L->r[low];//子表的第一个记录当作枢轴记录
     8 
     9     while (low < high)
    10     {
    11         //从右往左,找比枢轴记录关键字的值小的记录
    12         while (low < high && L->r[high] >= pivotkey)
    13             high--;
    14         swap(L, low, high);//将比枢轴记录小的记录交换到低端
    15 
    16         //从左往右,找比枢轴记录关键字的值大的记录
    17         while (low < high && L->r[low] <= pivotkey)
    18             low++;
    19         swap(L, low, high);//将比枢轴记录大的记录交换到高端
    20     }
    21 
    22     return low;//返回枢轴所在的位置
    23 }
     1 //对L->r[low,...,high]做快速排序
     2 void QSort(SqList* L, int low, int high)
     3 {
     4     int pivot;
     5     if (low < high)
     6     {
     7         pivot = Partition(L, low, high);//枢轴的位置
     8 
     9         QSort(L, low, pivot - 1);//对L->r[low,...,pivot - 1]递归排序
    10         QSort(L, pivot + 1, high);//对L->r[pivot,...,high]递归排序
    11     }
    12 }

      执行Partition函数后顺序表中的记录变化如下所示:

      上述操作使枢轴记录5到位,并返回其所在位置3,接下来,对低子表{3,1}和高子表{8,9}进行同样的操作,最终将顺序表排序为有序表。

      可以从一下几个方面对快速排序进行优化:

      (1)优化枢轴的选取。枢轴记录的选择,其值居于待排序记录的中间最好,然而,将子表的第一个记录当作枢轴记录,并不能保证其关键字的值居于待排序记录的中间,所以衍生出了三数取中,九数取中等优化枢轴的选取的方法。我们选择三数取中法来对快速排序进行优化,即取待排序记录的左中右三个位置(也可以按其他方式取)的记录中关键字的值居中的记录作为枢轴记录。

      (2)优化不必要的交换。如上所示,选定的数轴5的最终位置为3,而我们在将枢轴记录放到该正确的位置的过程中,不断地调整枢轴的位置,也就是不断地进行交换,这些交换都是不必要的,我么可以采用替换操作来代替交换操作,当找到枢轴的位置时,将枢轴值存入该位置。

      (3)优化小数组的排序。当数组较小时,直接插入排序的性能更好,所以可以在代码中加入判断条件,当数组较小时,选用直接插入排序;当数组较大时,选用快速排序。

      (4)优化递归操作。栈的大小是有限的,且每次递归调用都会占用一定的栈空间,函数的参数越多,占用的栈空间越大,所以可以通过减少递归来提高程序的性能。我们采用尾递归来减少递归次数。

      优化的快速排序的代码如下所示:

     1 //交换顺序表L中的记录,使枢轴记录放到正确位置,并返回其所在位置
     2 //交换结束后,枢轴记录前面的记录值小于枢轴记录的值
     3 //后面的记录值大于枢轴记录的值
     4 int Partition(SqList* L, int low, int high)
     5 {
     6     int pivotkey;
     7 
     8     /********************************************************/
     9     //优化枢纽的选取
    10     int mid = (low + high) / 2;
    11     if (L->r[low] > L->r[high])
    12         swap(L, low, high);
    13     if (L->r[mid] > L->r[high])
    14         swap(L, high, mid);
    15     if (L->r[mid] > L->r[low])
    16         swap(L, mid, low);
    17     /********************************************************/
    18 
    19     pivotkey = L->r[low];
    20 
    21     /********************************************************/
    22     //优化不必要的交换
    23     L->r[0] = pivotkey;
    24     /********************************************************/
    25 
    26     while (low < high)
    27     {
    28         while (low < high && L->r[high] >= pivotkey)
    29             high--;
    30 
    31         /********************************************************/
    32         //优化不必要的交换
    33         L->r[low] = L->r[high];
    34         /********************************************************/
    35 
    36         swap(L, low, high);
    37         while (low < high && L->r[low] <= pivotkey)
    38             low++;
    39 
    40         /********************************************************/
    41         //优化不必要的交换
    42         L -> r[high] = L->r[low];
    43         /********************************************************/
    44 
    45         swap(L, low, high);
    46     }
    47 
    48     /********************************************************/
    49     //优化不必要的交换
    50     L->r[low] = L->r[0];
    51     /********************************************************/
    52 
    53     return low;
    54 }
     1 //对L->r[low,...,high]做快速排序
     2 void QSort(SqList *L,int low,int high)
     3 {
     4     int pivot;
     5 
     6     /********************************************************/
     7     //优化递归操作
     8     while (low < high)
     9     /********************************************************/
    10     {
    11         pivot = Partition(L, low, high);//枢轴的位置
    12 
    13         QSort(L, low, pivot - 1);//对L->r[low,...,pivot - 1]递归排序
    14 
    15         /********************************************************/
    16         //优化递归操作
    17         low = pivot + 1;//尾递归
    18         /********************************************************/
    19     }
    20 }

      

      执行Partition函数后顺序表中的记录变化如下所示:

      到此为止,我们介绍完了所有的排序算法,下一次会对所有的排序算法进行一个总结,对各种排序算法进行比较,分析其时间复杂度以及适用情况。接下来会依次介绍查找算法,希望给位同侪可以多多关注,给出指导意见,多多交流!

    相关链接:

    冒泡排序 https://www.cnblogs.com/yongjin-hou/p/13858510.html

    简单选择排序 https://www.cnblogs.com/yongjin-hou/p/13859148.html
    直接插入排序 https://www.cnblogs.com/yongjin-hou/p/13861458.html
    希尔排序 https://www.cnblogs.com/yongjin-hou/p/13866344.html

    堆排序 https://www.cnblogs.com/yongjin-hou/p/13873770.html

    归并排序 https://www.cnblogs.com/yongjin-hou/p/13921147.html

    参考书籍:程杰 著,《大话数据结构》,清华大学出版社。

  • 相关阅读:
    基于结构化平均感知机的分词器Java实现
    HanLP分词命名实体提取详解
    [英语学习]王秒同学《21天TED英语精练团》
    [不好分类]转帖:好好说话是个“技术活”(李笑来说话太直了?)
    [英语学习]3招速成英语发音 背景音乐和学习随感
    [读书笔记]《番茄工作法图解:简单易行的时间管理方法》
    [英语学习]给宝宝的英语原版资源
    [办公自动化]如何判断服务器是否开放某端口
    [他山之石]Google's Project Oxygen Pumps Fresh Air Into Management
    [读书笔记]云计算时代的网络,读《腾云,云计算和大数据时代网络技术揭秘》
  • 原文地址:https://www.cnblogs.com/yongjin-hou/p/13950379.html
Copyright © 2011-2022 走看看