小小c#算法题 - 6 - 快速排序 (QuickSort)
快速排序是排序算法中效率比较高的一种,也是面试常被问到的问题。
快速排序(Quick Sort)是对冒泡排序的一种改进。它的基本思想是,通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。(数据结构,严蔚敏)。
更具体一点的说,首先我们从待排序列中选取一个元素作为支点(pivot),这个支点的选择可以任意选取,所以经常直接拿第一个元素作为支点,更好一点的办法是三者取中法,即取第一个元素,最后一个元素,中间一个元素,这三个值中间的中值(非最大最小)作为支点。支点选好之后,把支点放到待排序序列的第一个位置,如果你选的是第一个元素作为支点的话,不用做什么,如果是其他情况,那么就把选好的支点跟第一个元素交换一下。然后通过代码将所有比支点小的记录都放在它之前的位置,将所有比它大的记录都放到它的位置之后。由此最后可以以该支点的位置作分界线,将序列分割成两个子序列。这个过程我们称为一趟快速排序(或一次划分)。
一次快速排序的具体实现:
将支点放在序列的第一个位置,最左边。然后从高位下标high(初始值为最后一个元素的位置)开始往前搜索,找到第一个小于支点的元素,将其和支点元素交换,即把一个比支点小的元素放在了支点的位置,而支点现在所处的新位置之后的元素都是比其大的,因为这个位置是我们从高位找到第一个比支点小的元素的原先位置;然后从低位low(初始值为第一个元素的位置)开始往后搜索,找到第一个大于支点的记录,将其和支点元素交换,由于前面的交换中支点所处的位置之后的元素都比其大,通过这一次的交换的话,这个较大的元素现在所在的位置往后的元素都是大于支点的,而且,支点回到的新的位置之前的元素都是比支点小的。重复这两步,直到从低位搜索和从高位搜索的两个index(也可以理解为指针)相遇,即low == high。
其实,上面提到的每次交换元素的操作可以精简一下,对支点记录的赋值是多余的,因为只有在一趟排序结束时,才能确定支点的最后位置。所以有一个临时变量将支点的值记录下来就可以了。每次交换时,只把需要变换位置的元素放到新的位置就可以了。
下面是代码,这段代码采用第一个元素作为支点,如果没有用第一个元素作为支点的话,那么交换一下,把支点放到第一个位置即可,然后采用下面相同的代码:
static int Partition(int[] numbers, int low, int high)
{
int pivot = numbers[low];
while (low < high)
{
while (low < high && numbers[high] >= pivot)
{
high--;
} numbers[low] = numbers[high]; while (low < high && numbers[low] <= pivot)
{
low++;
}
numbers[high] = numbers[low];
} numbers[low] = pivot;
return low;
}
上面是一次快速排序的代码,最后返回的是支点的位置。下面就是对支点左右两边的序列分别进行快速排序,当子序列只有两个元素时,再通过一次排序该子序列就是有序的了,由此实现整个序列有序。可见,这是一个递归的操作。只有当序列长度大于1时才进行快速排序,因为只有一个元素的序列肯定是有序的,所以跳出递归的条件是low<high。只有一个元素时,low 是等于 high的。
static void QuickSort(int[] numbers, int low, int high)
{
if (low < high)
{
int partitionLocation = Partition(numbers, low, high);
QuickSort(numbers, low, partitionLocation - );
QuickSort(numbers, partitionLocation + , high);
}
}
调用的过程就如:
static void Main(string[] args)
{
int[] numbers = { , , , , , , , };
QuickSort(numbers, , numbers.Length - );
}
就平均时间而言,快速排序是目前认为是最好的一种内部排序方法。(数据结构,严蔚敏)。
最后,快速排序的平均时间复杂度是O(nlogn),最坏情况是O(n2),如序列本身就有序时,将蜕变为冒泡排序。空间复杂度为O(logn),这是因为递归过程要维护一个栈。
如果不好理解的话,最好的办法就是对着代码,手动走几遍,或者找些有配图的书或文章看看。
小小c#算法题 - 6 - 快速排序 (QuickSort)的更多相关文章
- 小小c#算法题 - 11 - 二叉树的构造及先序遍历、中序遍历、后序遍历
在上一篇文章 小小c#算法题 - 10 - 求树的深度中,用到了树的数据结构,树型结构是一类重要的非线性数据结构,树是以分支关系定义的层次结构,是n(n>=0)个结点的有限集.但在那篇文章中,只 ...
- 算法实例-C#-快速排序-QuickSort
算法实例 ##排序算法Sort## ### 快速排序QuickSort ### bing搜索结果 http://www.bing.com/knows/search?q=%E5%BF%AB%E9%80% ...
- 排序算法四:快速排序(Quicksort)
快速排序(Quicksort),因其排序之快而得名,虽然Ta的平均时间复杂度也是O(nlgn),但是从后续仿真结果看,TA要比归并排序和堆排序都要快. 快速排序也用到了分治思想. (一)算法实现 pr ...
- 小小c#算法题 - 7 - 堆排序 (Heap Sort)
在讨论堆排序之前,我们先来讨论一下另外一种排序算法——插入排序.插入排序的逻辑相当简单,先遍历一遍数组找到最小值,然后将这个最小值跟第一个元素交换.然后遍历第一个元素之后的n-1个元素,得到这n-1个 ...
- 小小c#算法题 - 12 - Joseph Circle(约瑟夫环)
约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数(从1开始报数),数到m的那个人出列:他的下一个人又从1开始报数,数到m的那个人又 ...
- 小小c#算法题 - 10 - 求树的深度
树型结构是一类重要的非线性数据结构,树是以分支关系定义的层次结构,是n(n>=0)个结点的有限集.关于树的基本概念不再作过多陈述,相信大家都有了解,如有遗忘,可翻书或去其他网页浏览以温习. 树中 ...
- 小小c#算法题 - 9 - 基数排序 (Radix Sort)
基数排序和前几篇博客中写到的排序方法完全不同.前面几种排序方法主要是通过关键字间的比较和移动记录这两种操作来实现排序的,而实现基数排序不需要进行记录项间的比较.而是把关键字按一定规则分布在不同的区域, ...
- 小小c#算法题 - 8 - 归并排序 (Merging Sort)
“归并”的含义是将两个或两个以上的有序序列组合成一个新的有序序列.这个“归并”可以在O(n+m)的数量级上实现,但这同时也需要O(n+m)的空间复杂度.具体为:首先分配一个新的长度为n+m的空序列,然 ...
- 快速排序(quicksort)算法实现
快速排序(quicksort)是分治法的典型例子,它的主要思想是将一个待排序的数组以数组的某一个元素X为轴,使这个轴的左侧元素都比X大,而右侧元素都比X小(从大到小排序).然后以这个X在变换后数组的位 ...
随机推荐
- cat echo 打印菜单
cat << END ============================= 1.apple 2.pear 3.banana ...
- Codeforces 358D Dima and Hares:dp【只考虑相邻元素】
题目链接:http://codeforces.com/problemset/problem/358/D 题意: 有n个物品A[i]摆成一排,你要按照某一个顺序将它们全部取走. 其中,取走A[i]的收益 ...
- 造成segmentation fault的可能原因分析
一 造成segment fault,产生core dump的可能原因 1.内存访问越界 a) 由于使用错误的下标,导致数组访问越界 b) 搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串 ...
- 关于pyhton中的__xxx__格式的方法与变量的理解
python中类似__xx__的方法和变量是python系统内定义的方法和变量,都是具有特殊意义的基础变量和方法,一般不要擅自使用,除非知道自己在干什么. 具体查看python内置模块builtins ...
- java try中包含return语句,finally中的return语句返回顺序
//结论: finally 中的代码比 return 和 break 语句后执行 public static void main(String[] args) { int x=new Test.tes ...
- OpenCV——饱和度调整
参考: 闲人阿发伯的博客 // define head function #ifndef PS_ALGORITHM_H_INCLUDED #define PS_ALGORITHM_H_INCLUDED ...
- OSS阿里云文件上传 demo。
所需jar包: aliyun-openservices-1.2.3.jar jdom-1.1.jar commons-codec-1.4.jar commons-logging-1.1.1.jar g ...
- poj 1845 Sumdiv(约数和,乘法逆元)
题目: 求AB的正约数之和. 输入: A,B(0<=A,B<=5*107) 输出: 一个整数,AB的正约数之和 mod 9901. 思路: 根据正整数唯一分解定理,若一个正整数表示为:A= ...
- BZOJ2563阿狸和桃子的游戏
2563: 阿狸和桃子的游戏 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 952 Solved: 682[Submit][Status][Discu ...
- backbonejs学习
文章: http://www.cnblogs.com/yexiaochai/archive/2013/07/27/3219402.html http://blog.csdn.net/cony100/a ...