1. 首页 > 智能数码 >

快速排序算法设计流程图 快速排序法排序过程图解

如何用ja实现快速排序,简答讲解下原理

快速排序思想:

快速排序算法设计流程图 快速排序法排序过程图解快速排序算法设计流程图 快速排序法排序过程图解


通过对数据元素Rn 进行一趟排序划分出独立的两个部分。其中一个部分的关键字比另一部分的关键字小。然后再分别对两个部分的关键字进行一趟排序,直到独立的元素只有一个,此时整个元素有序。

快速排序的过程,对一个元素R[ low ... high ] ,首先取一个数(一般是R[low] )做参照 , 以R[low]为基准重新排列所有的元素。

所有比R[low]小的放前面,所有比R[low] 大的放后面,然后以R[low]为分界,对R[low ... high] 划分为两个子集和,再做划分。直到low >= high 。

比如:对R={37, 40, 38, 42, 461, 5, 7, 9, 12}进行一趟快速排序的过程如下(注:下面描述的内容中元素下表从 0 开始):

开始选取基准 base = 37,初始位置下表 low = 0 , high = 8 , 从high=8,开始如果R[8] < base , 将high位置中的内容写入到R[low]中, 将high位置空出来, low = low +1 ;

从low开始探测,由于low=1 , R[low] > base ,所以将R[low]写入到R[high] , high = high -1 ;

检测到low < high ,所以第一趟快速排序仍需继续:

此时low=1,high=7,因为 R[high] < base ,所以将 R[high] 写入到到R[low]中,low = low + 1;

从low开始探测,low = 2 , R[low] >base ,所以讲R[low]写入到R[high],high=high-1;

继续检测到 low 小于high

此时low=2,high=6,同理R[high] < base ,将R[high] 写入到R[low]中,low=low+1;

从low继续探测,low = 3 , high=6 , R[low] > base , 将R[low]写入到R[high]中,high = high-1;

继续探测到low小于high

此时low=3,high=5,同理R[high] < base,将R[high]写入到R[low]中,low = low +1;

从low继续探测,low = 4,high=5,由于R[low] > base , 将R[low]写入到R[high]中,high = high -1 ;

此时探测到low == high == 4 ;该位置即是base所在的位置,将base写入到该位置中.

然后再对子序列Rs1 = {12,9,7,5} 和 Rs2={461,42,38,40}做一趟快速排序,直到Rsi中只有一个元素,或没有元素。

快速排序的Ja实现:

private static boolean isEmpty(int[] n) {

return n == null || n.length == 0;

}// ///////////////////////////////////////////////////

/

快速排序算法思想——挖坑填数方法:

@param n 待排序的数组

/

public static void quickSort(int[] n) {

if (isEmpty(n))

return;

quickSort(n, 0, n.length - 1);

}public static void quickSort(int[] n, int l, int h) {

if (isEmpty(n))

return;

if (l < h) {

int pivot = partion(n, l, h);

quickSort(n, l, pivot - 1);

quickSort(n, pivot + 1, h);

}}

private static int partion(int[] n, int start, int end) {

int tmp = n[start];

while (start < end) {

while (n[end] >= tmp && start < end)

end--;

if (start < end) {

n[start++] = n[end];

}while (n[start] < tmp && start < end)

start++;

if (start < end) {

n[end--] = n[start];

}}

n[start] = tmp;

return start;

}在代码中有这样一个函数:

public static void quickSortSwap(int[] n, int l, int h)

该函数可以实现,元素定的 l 到 h 位置间的数据元素进行排序。

快速排序

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

快速排序算法通过多次比较和交换来实现排序,其排序流程如下:

(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。

(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。

(3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理

(4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。

下面通过一个例子介绍快速排序算法的思想,假设要对数组a[10]={6,1,2,7,9,3,4,5,10,8}进行排序,首先要在数组中选择一个数作为基准值,这个数可以随意选择,在这里,我们选择数组的第一个元素a[0]=6作为基准值,接下来,我们需要把数组中小于6的数放在左边,大于6的数放在右边,怎么实现呢?

我们设置两个“哨兵”,记为“哨兵i”和“哨兵j”,他们分别指向数组的第一个元素和后一个元素,即i=0,j=9。首先哨兵j开始出动,哨兵j一步一步地向左挪动(即j–),直到找到一个小于6的数停下来。接下来哨兵i再一步一步向右挪动(即i++),直到找到一个数大于6的数停下来。

后哨兵j停在了数字5面前,哨兵i停在了数字7面前。此时就需要交换i和j指向的元素的值。

交换之后的数组变为a[10]={6,1,2,5,9,3,4,7,10,8}:

第一次交换至此结束。接下来,由于哨兵i和哨兵j还没有相遇,于是哨兵j继续向前,发现比6小的4之后停下;哨兵i继续向前,发现比6大的9之后停下,两者再进行交换。交换之后的数组变为a[10]={6,1,2,5,4,3,9,7,10,8}。

第二次交换至此结束。接下来,哨兵j继续向前,发小比6小的3停下来;哨兵i继续向前,发现i==j了!!!于是,这一轮的探测就要结束了,此时交换a[i]与基准的值,数组a就以6为分界线,分成了小于6和大于6的左右两部分:a[10]={3,1,2,5,4,6,9,7,10,8}。

至此,第一轮快速排序完全结束,接下来,对于6左边的半部分3,1,2,5,4,执行以上过程;对于6右边的半部分9,7,10,8,执行以上过程,直到不可拆分出新的子序列为止。终将会得到这样的序列:1 2 3 4 5 6 7 8 9 10,到此,排序完全结束。

快速排序的一次划分算法从两头交替搜索,直到low和hight重合,因此其时间复杂度是O(n);而整个快速排序算法的时间复杂度与划分的趟数有关。

理想的情况是,每次划分所选择的中间数恰好将当前序列几乎等分,经过log 2 n趟划分,便可得到长度为1的子表。这样,整个算法的时间复杂度为O(nlog 2 n)。

坏的情况是,每次所选的中间数是当前序列中的或小元素,这使得每次划分所得的子表中一个为空表,另一子表的长度为原表的长度-1。这样,长度为n的数据表的快速排序需要经过n趟划分,使得整个排序算法的时间复杂度为O(n 2 )。

为改善坏情况下的时间性能,可采用其他方法选取中间数。通常采用“三者值取中”方法,即比较H->r[low].key、H->r[high].key与H->r[(low+high)/2].key,取三者中关键字为中值的元素为中间数。

可以证明,快速排序的平均时间复杂度也是O(nlog 2 n)。因此,该排序方法被认为是目前的一种内部排序方法

数据结构 第6题快速排序前两趟 第一趟写对了,但第二趟我写的与答案不一样 求解释

第二趟排序是,以25为分割,将15、10、20、18、5、3、16和44、64、100、81、38、40、31分成两组分别进行快速排序即得到第二趟的正确排序。而不是将整个一组数据进行排序算法,不然就得到你的排序结果了。

//使用val对a数组从fromIndex(包含)至toIndex(不包含)位置进行数据填充

public static void fill(long[] a, int fromIndex, int toIndex, long val) {

rangeCheck(a.length, fromIndex, toIndex);

for (int i=fromIndex; i

a[i] = val;

}

快速排序复杂度

快速排序的时间性能取决于快速排序递归的深度,可以用递归树来描述递归算法的执行情况。

情况

如图9‐9‐7所示,它是{50,10,90,30, 70,40,80,60,20}在快速排序过程中的递归过程。由于我们的第一个关键字是50,正好是待排序的序列的中间值,因此递归树是平衡的,此时性能也比较好。

在情况下,Partition每次都划分得很均匀,如果排序n个关键字,其递归树的深度就为.log2n.+1(.x.表示不大于x的整数),即仅需递归log2n次,需要时间为T(n)。第一次Partiation需要对整个数组扫描一遍,做n次比较。然后,获得的枢轴将数组一分为二,那么各自还需要T(n/2)的时间(注意是情况,所以平分两半)。于是不断地划分下去,我们就有了下面的不等式推断。

T(n)≤2T(n/2) +n,T(1)=0 T(n)≤2(2T(n/4)+n/2) +n=4T(n/4)+2n

也就是说,在的情况下,快速排序算法的时间复杂度为O(nlogn)。

坏情况

在坏的情况下,待排序的序列为正序或者逆序,每次划分只得到一个比上一次划分少一个记录的子序列,注意另一个为空。如果递归树画出来,它就是一棵斜树。此时需要执行n‐1次递归调用,且第i次划分需要经过n‐i次关键字的比较才能找到第i个记录,也就是枢轴的位置,因此比较次数为

终其时间复杂度为O(n2)。

平均情况

平均的情况,设枢轴的关键字应该在第k的位置(1≤k≤n),那么:

由数学归纳法可证明,其数量级为O(nlogn)。

快速排序算法c语言

排序算法是《数据结构与算法》中基本的算法之一。

排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。用一张图概括:

点击以下图片查看大图:

关于时间复杂度

平方阶 (O(n2)) 排序 各类简单排序:直接插入、直接选择和冒泡排序。

线性对数阶 (O(nlog2n)) 排序 快速排序、堆排序和归并排序;

O(n1+§)) 排序,§ 是介于 0 和 1 之间的常数。 希尔排序

线性阶 (O(n)) 排序 基数排序,此外还有桶、箱排序。

关于稳定性

稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序。

不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序。

名词解释:

n:数据规模 k:"桶"的个数 In-place:占用常数内存,不占用额外内存 Out-place:占用额外内存 稳定性:排序后 2 个相等键值的顺序和排序之前它们的顺序相同

包含以下内容:

1、冒泡排序 2、选择排序 3、插入排序 4、希尔排序 5、归并排序 6、快速排序 7、堆排序 8、计数排序 9、桶排序 10、基数排序

排序算法包含的相关内容具体如下:

冒泡排序算法

冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。

选择排序算法

选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n?) 的时间复杂度。所以用到它的时候,数据规模越小越好。的好处可能就是不占用额外的内存空间。

插入排序算法

插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。插入排序是一种简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

希尔排序算法

希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。

归并排序算法

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

快速排序算法

快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很地被实现出来。

堆排序算法

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。

计数排序算法

计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。

桶排序算法

桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。

基数排序算法

基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

快速排序和冒泡排序算法

此前由于自己对快速排序算法的认识不够,现在重新学习一遍,加深自己的认识。

快速排序算法是对冒泡算法的一种改进,大家都知道,冒泡排序是比较相邻元素的大小,而快速排序则在冒泡排序的基础上将数组分为两部分,在分别对他们进行排序,通过递归实现。

冒泡排序的实现过程:

快速排序的思想是在一个需要排序的数组A中首先选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的树都放到它左边,所有比它大的数都放到它右边,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法。

一般快速排序的算法是:

快速排序实现过程:

总结:快速排序和冒泡排序各有优缺点,不过快排时间复杂度是o(nlogn),而冒牌排序在坏的情况下的时间复杂度是o(n2),所以快速排序在提升效率上快了不少。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至836084111@qq.com 举报,一经查实,本站将立刻删除。

联系我们

工作日:9:30-18:30,节假日休息