我们考虑一个问题。如果要排序的数组本身就是有序的,例如:1, 2, 3, 4, 5。用上面的方法排序会发生什么情况?

基准数是1,东东从右边开始往左边走,结果一直走到最左边,遇到了虫虫才停止,这个过程中,虫虫根本没有机会移动。也就是说这个基准数本来就在正确的位置。这时这个数组只能被分为两部分,而不是希望的三部分。除了基准数之外,剩下的一部分仅仅比原数组少了一个元素。而这个过程的时间复杂度为O(N),接下去继续,结果发现每次得到的新数组都仅仅比原先少一个元素,所以一共需要进行N次。这个过程与冒泡排序的运行过程是一样的。也就是说快速排序在遇到有序的数组时会退化成冒泡排序,所以时间复杂度为O(N2)。遇到这样的问题,我们该怎么办呢?
如果不管三七二十一,我们先把这个数组的最左边的元素与中间元素进行交换,得到一个新数组:3, 1, 2, 4, 5。这时再用上面的方法进行排序,就可以把数组分成三段。时间复杂度可以重新回到O(N * logN)。

这是改进后的快速排序,与原始的快速排序代码相比,仅仅多了两行代码:

void quickSort(int arr[], int low, int high)
{if(low > high) //递归的出口{return;}//如果要排序的数组是有序的。用原始的快速排序方法会导致退化成冒泡排序 //这时如果把中间的元素跟low的元素交换,则每次都能把数组分成几乎相等的两份//增加这两行代码后就可以把时间复杂度重新变为O(N * logN)了。int middle = low + (high - low) / 2; //求中间元素的下标,不要写成 (low + high) / 2swap(middle, low);int num = arr[low];int i = low; //虫虫在最左边 int j = high; //东东在最右边 while(i < j) //虫虫和东东没有相遇的时候继续走 {//虫虫是哥哥,要让着弟弟,所以每次都是东东先走。 while(i < j && num <= arr[j]) //没有相遇,且右边的元素比基准大 {j--; //东东往左走一步 }while(i < j && num >= arr[i]) //没有相遇,且左边的元素比基准大{i++; //虫虫往右走一步}if(i < j) //两个小朋友都停止的时候,如果他们还没有相遇 {swap(i, j); //说明还没有到家,两个元素交换一下。虫虫和东东没有交换哦 }}//i==j时,虫虫和东东帮基准元素找到家了 //交换一下基准和家里的元素,也就是让基准元素回家,把家里的元素放到最前面 swap(low, i);  //递归函数的等价关系式:用同样的方法帮左边和右边的两段数据排序 quickSort(arr, low, i-1); //左边一段数组继续排序 quickSort(arr, i+1, high); //右边一段数组继续排序
}

选择中间的元素作为基准,或者随机选择一个元素作为基准,这个方法就能解决待排序的数组有序 (升序和降序均可) 时算法退化的问题了。但是这个改进仍然不能解决所有数据都相同时,算法成冒泡排序的问题。下一节,我们将解决这个问题。

快速排序的优化1: 选取中间值或随机值作为基准,C语言实现相关推荐

  1. 快速排序及优化(Java实现)

    一. 普通快速排序 找一个基准值base,然后一趟排序后让base左边的数都小于base,base右边的数都大于等于base.再分为两个子数组的排序.如此递归下去. public class Quic ...

  2. 快速排序深度优化详解

    正如它的名字所体现,快速排序是在实践中最快的已知排序算法,平均运行时间为O(NlogN),最坏的运行时间为O(N^2).算法的基本思想很简单,然而想要写出一个高效的快速排序算法并不是那么简单.基准的选 ...

  3. 三种快速排序以及快速排序的优化

    1.快速排序的基本思想: 快速排序使用分治的思想,通过一趟排序将待排序列分割成两部分,其中一部分记录的关键字均比另一部分记录的关键字小.之后分别对这两部分记录继续进行排序,以达到整个序列有序的目的. ...

  4. java版排序算法简介及冒泡排序以及优化,选择排序,直接插入排序,希尔排序,堆排序,快速排序及其优化前言 2 分类 2 稳定性 3 时间复杂度 4 Java实现版本 5 1、冒泡排序 6 2、选择排序

    好吧 ~~csdn太难用了....尼玛...写了半天的也无法弄进去...lz正在找更好地博客,or放在github上打算.. 下边是lz自己的有道云分享,大概内容是 http://note.youda ...

  5. C++基础知识(二)--左值右值--逻辑表达式求值优化--逗号运算符与表示式--输入输出格式控制...

    :一.C++左值右值概念 左值:c++将变量名代表的单元称为左值,而将变量的值称为右值,左值必须是内存中可以访问且可以合法修改的对象,因此只能是变量名,而不能是常量或表达式.即左值可以寻址. 右值:将 ...

  6. 八十一、最快最优的快速排序和优化

    @Author:Runsen 编程的本质来源于算法,而算法的本质来源于数学,编程只不过将数学题进行代码化. ---- Runsen 快速排序 不久前,我在牛客中看到这样一个笑话,面试官让他写一个快速排 ...

  7. 当前方法的代码已经过优化,因此无法计算表达式的值

    当前方法的代码已经过优化,因此无法计算表达式的值 /************************************************************************** ...

  8. 单目标应用:白鲸优化算法(Beluga whale optimization,BWO)优化双向长短时记忆BiLSTM的权值和阈值(提供MATLAB代码)

    一.算法简介 白鲸优化算法(Beluga whale optimization,BWO)由Changting Zhong等人于2022年提出,该算法模拟了白鲸游泳,觅食和"鲸鱼坠落" ...

  9. seo优化怎样选取网站关键词?关键词如何设置?

    我们知道,seo优化是网站推广的方式之一,其主要形式来源于网站关键词排名,什么是关键词排名这里不多说,已经聊过了.那么,这个关键词是什么样的关键词,大家理所应当的想到,自己的产品自己的服务自己的牌子呗 ...

最新文章

  1. 引用 提高开发水平的几项必备技术
  2. 广东海洋大学计算机科学与技术排名,最新排名!广东高校22个学科位居全球前50位...
  3. 嵌入式闪存您了解多少?听听专家怎么说!
  4. 微信小程序,你的场景呢?
  5. Spring Cloud sleuth with zipkin over RabbitMQ教程
  6. 运行数据区②---堆
  7. 实现图片打乱_2020 回顾 | 25张图片,记录潮州的这一年
  8. 在没人相信的时候,你的坚持才真正可贵
  9. 快速迁移数据中心:华为云数据库SQL Server实践案例技术解析
  10. 多对多关联映射(双向关联)见项目:me_many_to_many
  11. webpack教程——css的加载
  12. android焦点动画,Android编程中PopupWindow的用法分析【位置、动画、焦点】
  13. linux下通过伪造udp包来实现指定网卡发送数据
  14. 在地图上点击一下,在图层上画一个点,并显示相关的信息
  15. 求助:ATI HD3200 LINUX驱动
  16. 手把手教你安装Sketch破解版和measure插件
  17. phpspider 的简单使用
  18. 3dmax如何删除多余的时间帧
  19. PyQt5 小工具:Excel数据分组汇总器...
  20. 人民币对美元汇率中间价报6.7472元 上调469个基点

热门文章

  1. 微积分:如何理解方向导数与梯度?
  2. read函数的 用法
  3. 位置度最大实体计算方式
  4. 嵌入式操作系统的基本概念
  5. 糊里糊涂违背了规则,硅胶制品很是懊悔
  6. 【C++探索之旅】开宗明义+第一部分第一课:什么是C++?
  7. mysql篇:如何进入mysql
  8. 数字逻辑笔记4逻辑代数的基本定理和规则
  9. 中国的各地节日美食都又哪些
  10. Eclipse开发工具的基本介绍及使用