热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

快速排序里的学问:快速排序的过程

通过前面问题以及引入了“信息熵”的概念,我们可以重新来理解排序的本质:一组未排序的N个数字,它们一共有N!种重排,其中只有一种排列是满足题意的(譬如从大到小排列)。换句话说,排序问题的可能性一共有N!种。任何基于比较的排序的基本操作单元都是“比较a和b”,这就相当于猜数字游戏里面的一个问句。

通过前面问题以及引入了“信息熵”的概念,我们可以重新来理解排序的本质:

一组未排序的N个数字,它们一共有N!种重排,其中只有一种排列是满足题意的(譬如从大到小排列)。

换句话说,排序问题的可能性一共有N!种。任何基于比较的排序的基本操作单元都是“比较a和b”,这就相当于猜数字游戏里面的一个问句,显然这个问句的答案只能是“是”或“否”,一个只有两种输出的问题最多只能将可能性空间切成两半,根据上面的思路,最佳切法就是切成1/2和1/2(将数组切成一半)。也就是说,我们希望在比较了a和b的大小关系之后,如果发现a b也是剩下N!/2种可能性。

由于假设每种排列的概率是均等的,所以这也就意味着支持a b的也是N!/2个,换言之,a b的概率。

我们希望每次在比较a和b的时候,a b的概率是均等的,这样我们就能保证无论如何都能将可能性缩小为原来的一半的最优下界。

一个直接的推论是,如果每次都像上面这样的完美比较,那么N个元素的N!种可能排列只需要log2N!就排查完了,而log2N!近似于NlogN。这正是快排的复杂度。

快速排序的实现

我们先理解一下快速排序的工作机制吧,下面是《算法导论》里的快排:

QUICKSORT(A, p, r)
 if p 

快速排序算法的关键是PARTITION过程,它对A[p..r]进行就地重排:

PARTITION(A, p, r)
  x ← A[r]
  i ← p - 1
  for j ← p to r - 1
       do if A[j] ≤ x
             then i ← i + 1
                  exchange A[i] <-> A[j]
  exchange A[i + 1] <-> A[r]
  return i + 1

我们将上面的过程用C语言描述一下:

#include "stdio.h"
#include "math.h"
#include "stdlib.h"

void PrintArray(int *arr);
void swap(int *a,int *b);

int num = 10;

void QuickSort(int *arr, int beg, int end)
{
	if(beg 

初始数组:59 40 55 92 73 69 27 79 3 30
    sentinel = arr[9] = 30
    arr[6](27) <= sentinel(30)
    arr[8](3) <= sentinel(30)
排序过程:27 3 30 92 73 69 59 79 40 55
    sentinel = arr[1] = 3
排序过程:3 27 30 92 73 69 59 79 40 55
    sentinel = arr[9] = 55
    arr[8](40) <= sentinel(55)
排序过程:3 27 30 40 55 69 59 79 92 73
    sentinel = arr[9] = 73
    arr[5](69) <= sentinel(73)
    arr[6](59) <= sentinel(73)
排序过程:3 27 30 40 55 69 59 73 92 79
    sentinel = arr[6] = 59
排序过程:3 27 30 40 55 59 69 73 92 79
    sentinel = arr[9] = 79
排序过程:3 27 30 40 55 59 69 73 79 92
最后结果:3 27 30 40 55 59 69 73 79 92
Process returned 0 (0x0)   execution time : 0.564 s
Press any key to continue.

从程序的运行结果我们就可以很清晰地看出快速排序的工作工程:

  1. 定点sentinel设为数组最后一个元素30
  2. 把比30小的划成一个小组(27,3,30),并把它们放在数组的前面。
  3. 定点sentinel设为小组的最后一个,不包含30,即(27,3)中的3。
  4. 对小组原地排序,即(3,27)。这样就完成这个小组的排序了(3,27,30)。
  5. 定点sentinel再次设为数组最后一个元素55。
  6. 把小于55的元素找出来划分为另外的小组(40)。
  7. 那个小组的排序也已经完成(40,55)。
  8. 定点再设为73,同样分组(69,59,73),排序为(59,69,73)。
  9. 定点再设为79,分组(79)
  10. 完成排序:3 27 30 40 55 59 69 73 79 92

总结下快排的过程:随机选择一个元素做“轴元素”(上面的定点sentinel),将所有小于轴元素的移到左边,其余移到右边。根据这个过程,快排的第一次比较就是将一个元素和轴元素比较,这个时候显而易见的是,“大于”和“小于”的可能性各占一半。这是一次漂亮的比较。

延伸阅读

此文章所在专题列表如下:

  1. 快速排序里的学问:从猜数字开始
  2. 快速排序里的学问:再看看称球问题
  3. 快速排序里的学问:信息熵
  4. 快速排序里的学问:快速排序的过程
  5. 快速排序里的学问:霍尔与快速排序
  6. 快速排序里的学问:霍尔快排的实现
  7. 快速排序里的学问:枢纽元选择与算法效率
  8. 快速排序里的学问:随机化快排

本文地址:http://www.nowamagic.net/librarys/veda/detail/2390,欢迎访问原出处。


推荐阅读
  • 本文介绍如何利用栈数据结构在C++中判断字符串中的括号是否匹配。通过顺序栈和链栈两种方式实现,并详细解释了算法的核心思想和具体实现步骤。 ... [详细]
  • 本文探讨了如何使用自增和自减运算符遍历二维数组中的元素。通过实例详细解释了指针与二维数组结合使用的正确方法,并解答了常见的错误用法。 ... [详细]
  • Søren Kierkegaard famously stated that life can only be understood in retrospect but must be lived moving forward. This perspective delves into the intricate relationship between our lived experiences and our reflections on them. ... [详细]
  • 本文介绍了几种不同的编程方法来计算从1到n的自然数之和,包括循环、递归、面向对象以及模板元编程等技术。每种方法都有其特点和适用场景。 ... [详细]
  • 本文探讨了高质量C/C++编程的最佳实践,并详细分析了常见的内存错误及其解决方案。通过深入理解内存管理和故障排除技巧,开发者可以编写更健壮的程序。 ... [详细]
  • 在Java中,this是一个引用当前对象的关键字。如何通过this获取并显示其所指向的对象的属性和方法?本文详细解释了this的用法及其背后的原理。 ... [详细]
  • 本文详细介绍了C语言中的指针,包括其基本概念、应用场景以及使用时的优缺点。同时,通过实例解析了指针在内存管理、数组操作、函数调用等方面的具体应用,并探讨了指针的安全性问题。 ... [详细]
  • C语言标准及其GCC编译器版本
    编程语言的发展离不开持续的维护和更新。本文将探讨C语言的标准演变以及GCC编译器如何支持这些标准,确保其与时俱进,满足现代开发需求。 ... [详细]
  • 解析SQL查询结果的排序问题及其解决方案
    本文探讨了为什么某些SQL查询返回的数据集未能按预期顺序排列,并提供了详细的解决方案,帮助开发者理解并解决这一常见问题。 ... [详细]
  • C语言基础入门:7个经典小程序助你快速掌握编程技巧
    本文精选了7个经典的C语言小程序,旨在帮助初学者快速掌握编程基础。通过这些程序的实践,你将更深入地理解C语言的核心概念和语法结构。 ... [详细]
  • Python 学习是否需要先掌握 C 语言?
    Python 是一门非常适合编程入门的语言,很多人疑惑是否需要先学习 C 语言才能更好地掌握 Python。本文将详细探讨这个问题,并为初学者提供专业的建议。 ... [详细]
  • 本文详细介绍了C语言的起源、发展及其标准化过程,涵盖了从早期的BCPL和B语言到现代C语言的演变,并探讨了其在操作系统和跨平台编程中的重要地位。 ... [详细]
  • 编写了几个500行左右代码的程序,但基本上解决问题还是面向过程的思维,如何从问题中抽象出类,形成类的划分和设计,从而用面向对象的思维解决问题?有这方面的入门好书吗?最好是结合几个具体的案例分析的 ... [详细]
  • Python 内存管理机制详解
    本文深入探讨了Python的内存管理机制,涵盖了垃圾回收、引用计数和内存池机制。通过具体示例和专业解释,帮助读者理解Python如何高效地管理和释放内存资源。 ... [详细]
  • 主板IO用W83627THG,用VC如何取得CPU温度,系统温度,CPU风扇转速,VBat的电压. ... [详细]
author-avatar
爵士独舞
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有