总的说来,要直接默写出快速排序还是有一定难度的,因为本人就自己的理解对快速排序作了下白话解释,希望对大家理解有帮助,达到快速排序,快速搞定。
快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。
该方法的基本思想是:
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
虽然快速排序称为分治法,但分治法这三个字显然无法很好的概括快速排序的全部步骤。因此我的对快速排序作了进一步的说明:挖坑填数+分治法:
先来看实例吧,定义下面再给出(最好能用自己的话来总结定义,这样对实现代码会有帮助)。
以一个数组作为示例,取区间第一个数为基准数。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
72 | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 48 | 85 |
初始时,i = 0; j = 9; X = a[i] = 72
由于已经将a[0]中的数保存到X中,可以理解成在数组a[0]上挖了个坑,可以将其它数据填充到这来。
从j开始向前找一个比X小或等于X的数。当j=8,符合条件,将a[8]挖出再填到上一个坑a[0]中。a[0]=a[8]; i++; 这样一个坑a[0]就被搞定了,但又形成了一个新坑a[8],这怎么办了?简单,再找数字来填a[8]这个坑。这次从i开始向后找一个大于X的数,当i=3,符合条件,将a[3]挖出再填到上一个坑中a[8]=a[3]; j--;
数组变为:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
48 | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 88 | 85 |
i = 3; j = 7; X=72
再重复上面的步骤,先从后向前找,再从前向后找。
从j开始向前找,当j=5,符合条件,将a[5]挖出填到上一个坑中,a[3] = a[5]; i++;
从i开始向后找,当i=5时,由于i==j退出。
此时,i = j = 5,而a[5]刚好又是上次挖的坑,因此将X填入a[5]。
数组变为:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
48 | 6 | 57 | 42 | 60 | 72 | 83 | 73 | 88 | 85 |
可以看出a[5]前面的数字都小于它,a[5]后面的数字都大于它。因此再对a[0…4]和a[6…9]这二个子区间重复上述步骤就可以了。
对挖坑填数进行总结
1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。
2.j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。
3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。
4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。
照着这个总结很容易实现挖坑填数的代码:
- int AdjustArray(int s[], int l, int r) //返回调整后基准数的位置
- {
- int i = l, j = r;
- int x = s[l]; //s[l]即s[i]就是第一个坑
- while (i < j)
- {
- // 从右向左找小于x的数来填s[i]
- while(i < j && s[j] >= x)
- j--;
- if(i < j)
- {
- s[i] = s[j]; //将s[j]填到s[i]中,s[j]就形成了一个新的坑
- i++;
- }
- // 从左向右找大于或等于x的数来填s[j]
- while(i < j && s[i] < x)
- i++;
- if(i < j)
- {
- s[j] = s[i]; //将s[i]填到s[j]中,s[i]就形成了一个新的坑
- j--;
- }
- }
- //退出时,i等于j。将x填到这个坑中。
- s[i] = x;
- return i;
- }
再写分治法的代码:
- void quick_sort1(int s[], int l, int r)
- {
- if (l < r)
- {
- int i = AdjustArray(s, l, r);//先成挖坑填数法调整s[]
- quick_sort1(s, l, i - 1); // 递归调用
- quick_sort1(s, i + 1, r);
- }
- }
这样的代码显然不够简洁,对其组合整理下:
- //快速排序
- void quick_sort(int s[], int l, int r)
- {
- if (l < r)
- {
- //Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 参见注1
- int i = l, j = r, x = s[l];
- while (i < j)
- {
- while(i < j && s[j] >= x) // 从右向左找第一个小于x的数
- j--;
- if(i < j)
- s[i++] = s[j];
- while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数
- i++;
- if(i < j)
- s[j--] = s[i];
- }
- s[i] = x;
- quick_sort(s, l, i - 1); // 递归调用
- quick_sort(s, i + 1, r);
- }
- }
快速排序还有很多改进版本,如随机选择基准数,区间内数据较少时直接用另的方法排序以减小递归深度。有兴趣的筒子可以再深入的研究下。
注1,有的书上是以中间的数作为基准数的,要实现这个方便非常方便,直接将中间的数和第一个数进行交换就可以了。
转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/6684558
-
顶
- 53
-
踩
- 1
-
猜你在找
167楼 LOLERSB 前天 15:08发表 [回复]-
-
总算理解了快排的方法,谢谢楼主
166楼 skycode3 4天前 22:24发表 [回复]-
-
楼主,有个问题想请教下。
您的程序while循环:
if(i<j)
s[i++] = s[j];
中的if(i<j)这个判断意义在哪里呀?直接s[i++]=s[j]有什么问题吗?
Re: skycode3 4天前 23:35发表 [回复]-
-
回复tingxuelouwq:额,知道了为什么了,如果没有找到,则left=right,因此需要进行判断
165楼 的得德嘚 2016-03-02 19:43发表 [回复]-
-
int x = s[l]; //s[l]即s[i]就是第一个坑
小白问题:这里不该是s[0]是第一个坑吗?楼主这样不是s[1]成为第一个坑,那s[0]没有比到哎
Re: 看不清的天 2016-03-02 21:27发表 [回复]-
-
回复go_liyang:s[0]是第一个坑,把这个数拿出和后面的数一一作比较。
164楼 章鱼哥不吃蟹黄包 2016-02-03 22:58发表 [回复]-
-
博主写的太棒了!
163楼 heartacker 2016-02-02 12:44发表 [回复]-
-
小白想问一下。输入的int l 和int r 输入的是怎么值?
Re: 看不清的天 2016-03-02 21:23发表 [回复]-
-
回复heartacker:数组中的第一个数和最后一个数,通常为0,n-1;
162楼 TJU_LUNA 2016-01-25 09:44发表 [回复]-
-
大赞博主,传道授业解惑
161楼 wssy213 2015-12-28 11:03发表 [回复]-
-
如果去掉这些条件,将会导致 j 指向错误的位置;还可能导致数组访问越界。
比如,将里面两个 while 循环中的 i < j 条件去掉后,使用 3,1 这两个数据来测试,看看会是怎样的结果。
Re: wssy213 2015-12-28 11:04发表 [回复]-
-
回复u013350333:我这是回复 157 楼的...
160楼 xiaoluo91 2015-12-27 23:13发表 [回复]-
-
讲得很好
159楼 mingyunyuansu 2015-12-23 22:10发表 [回复]-
-
严蔚敏的书看得一头雾水。。。反正我是看博主的秒懂,还有其他的白话系列也非常清楚,学习一个
158楼 newbie_ten 2015-12-19 23:52发表 [回复]-
-
太棒了!是我这菜鸟想要的
157楼 march_on 2015-12-14 23:20发表 [回复]-
-
AjustArray函数里面 while(i < j && s[j] >= x) 这个语句中的i<j可以去掉嘛,为什么一定要加这个条件,可以解释下嘛多谢
156楼 svg3985 2015-12-11 16:14发表 [回复]-
-
博主在文中写的是小于等于X的全放左边,但是代码中实现的是大于等于X的全放右边,希望更改一下。
还有,谢谢精彩讲解!
155楼 kkkksqwx 2015-12-02 09:16发表 [回复]-
-
讲得很清晰,通俗易懂。大赞。
154楼 yinCheng3161 2015-11-27 20:01发表 [回复]-
-
看君一博文,胜读十年书!
153楼 huangdequan1982 2015-11-25 20:57发表 [回复]-
-
讲的好!很用心,很科学的解释了 复杂问题!!!
152楼 leeon_l 2015-11-23 15:47发表 [回复]-
-
填坑这个词用得好,看懂了,谢谢博主,么么哒,自己写个java的试试
151楼 十一期盖丽男 2015-11-04 16:10发表 [回复]-
-
讲解的很详细,明白了
150楼 touwangyi 2015-10-06 19:21发表 [回复]-
-
给楼主点赞
149楼 小小_渔夫 2015-10-04 22:06发表 [回复]-
-
148楼的算法有问题吧?
148楼 _还行_ 2015-09-30 14:59发表 [回复]-
-
[java]
view plain
copy
- /**
- * for循环的快速排序[只需要这一个方法]
- * @param array
- * @param start
- * @param end
- */
- private static void QuickSort(Integer[] array,int start,int end)
- {
- if(start<end)
- {
- int key=array[start];//初始化保存基元
- int i=start,j;//初始化i,j
- for(j=start+1;j<=end;j++){
-
- if(array[j]<key)//如果此处元素小于基元,则把此元素和i+1处元素交换,并将i加1,如大于或等于基元则继续循环
- {
- int temp=array[j];
- array[j]=array[i+1];
- array[i+1]=temp;
- i++;
- }
-
- }
- array[start]=array[i];//交换i处元素和基元
- array[i]=key;
- QuickSort(array, start, i-1);//递归调用
- QuickSort(array, i+1, end);
-
- }
- }
147楼 wwy599987 2015-09-29 17:18发表 [回复]-
-
非常感谢,想想自己还用了‘值互换’。。。。
146楼 湖心亭看雪 2015-09-23 12:38发表 [回复]-
-
看了好几篇文章了,看了这个终于看懂了,谢谢作者
145楼 hello__world-- 2015-09-21 16:32发表 [回复]-
-
楼主讲得太好了,很有帮助,谢谢楼主
144楼 jiangming7 2015-09-18 12:01发表 [回复]-
-
多谢博主, "挖坑填数"这个思路真是清晰易懂
143楼 arthaslonely 2015-09-16 17:27发表 [回复]-
-
非常好,通俗易懂,多谢。
142楼 qq_30872357 2015-09-15 17:46发表 [回复]-
-
感觉第二种写法中的程序 13行 s[i++] = s[j];
18行 s[j--] = s[i];
括号里面直接写i和j也行啊,不用I自加J和自减啊,用c#验证了一下,排序结果没有任何区别。
141楼 新记忆而 2015-09-10 00:08发表 [回复]-
-
你去看看i i++ ++i 三个有什么不同就明白了。。不谢
140楼 ly_rose 2015-09-04 20:26发表 [回复]-
-
跪谢楼主,写得太好了,看懂了,大赞
139楼 guo---er 2015-08-31 14:57发表 [回复]-
-
跪谢楼主,秒懂!
138楼 小丫521 2015-08-25 16:43发表 [回复]-
-
太赞了!
137楼 liaohailin1989 2015-08-21 22:08发表 [回复]-
-
我正在学习 要好好看看 前段时间看懂了 现在又忘记了 还是没有理解 谢谢楼主
136楼 watcherman1412 2015-08-05 21:36发表 [回复]-
-
楼主写得不错,新手学习学习
135楼 no_sunday 2015-08-05 10:38发表 [回复]-
-
太赞了,谢谢
134楼 rain8080 2015-08-03 11:40发表 [回复]-
-
public void quick_sort(int s[], int left, int right) //返回调整后基准数的位置
{
if(right >= 1 && left <=right)
{
int i = left, j = right;
int x = s[left]; //s[l]即s[i]就是第一个坑
while (i < j)
{
// 从右向左找小于x的数来填s[i]
while(i < j && s[j] >= x)
j--;
if(i < j)
{
s[i] = s[j]; //将s[j]填到s[i]中,s[j]就形成了一个新的坑
i++;
}
// 从左向右找大于或等于x的数来填s[j]
while(i < j && s[i] < x)
i++;
if(i < j)
{
s[j] = s[i]; //将s[i]填到s[j]中,s[i]就形成了一个新的坑
j--;
}
}
//退出时,i等于j。将x填到这个坑中。
s[i] = x;
quick_sort(s, left, i - 1); // 递归调用
quick_sort(s, i + 1, right);
}
else
{
return;
}
}
这个是调整过的最外层加了else
小菜鸟终于明白了快排,谢谢楼主
Re: 格物穷理 2015-11-24 11:54发表 [回复]-
-
回复rain8080:赞一个,原文中的代码递归少了个出口,导致出现递归跳不出来
133楼 rain8080 2015-08-03 11:32发表 [回复]-
-
弱弱的说一句:运行有问题
Re: TTLCcc 2015-08-21 15:33发表 [回复]-
-
回复rain8080:兄弟,你应该是参数传错了吧,L不能直接传数组的LENGTH 要减个11111111111
Re: TTLCcc 2015-08-21 15:34发表 [回复]-
-
回复TTLCcc:是RRRRRRRR
132楼 欢乐的工科小硕 2015-07-30 15:24发表 [回复]-
-
挖坑
131楼 ThankGodIFail 2015-07-27 18:00发表 [回复]-
-
谢谢楼主的用心
130楼 hwtc1990 2015-07-27 15:04发表 [回复]-
-
copy这本书的吧 《数据结构与算法 C语言实现》 科学出版社
还是说这本书是你写的?
129楼 rt12345678910 2015-07-23 13:45发表 [回复]-
-
怎么很厉害,一看就懂了,比书上讲的好
128楼 骑着炮弹进城 2015-07-23 09:31发表 [回复]-
-
这个挖坑算法讲的还真不错。。看懂了。。
127楼 tangqi233 2015-07-22 17:17发表 [回复]-
-
while(i < j && s[j] >= x) // 从右向左找第一个小于x的数
j--;
if(i < j)
s[i++] = s[j];
楼主为什么是赋值到i++不是i位置呢,i++不是坑的下一个位置了吗,看不懂了可以讲一下吗谢谢
126楼 _雨过之后 2015-07-22 14:18发表 [回复]-
-
看这10分钟顶看几天书...............哎
125楼 evolution_language 2015-07-13 17:19发表 [回复]-
-
对挖坑填数进行总结那一块的第四步,可不可以写成
当数组a[j]的值没有一个小于基准值的时候,那么这一阶段的排序宣告结束
124楼 synce 2015-06-29 07:27发表 [回复]-
-
为楼主点赞!写的不错!
123楼 hello涛咪 2015-06-16 11:26发表 [回复]-
-
有个问题啊,楼主,要是数组的第一个数比最后一个数大,那L>R,这下怎么办,还没排序就直接退出sort函数了。
Re: 依步_ 2015-06-24 16:30发表 [回复]-
-
回复hellotaomi:注意 l 和 r 是下标,而不是具体的数值。
122楼 hello涛咪 2015-06-16 11:06发表 [回复]-
-
楼主,当数组的第一个数比最后一个数大的话,如:int[] arr={23,11,55,18},那么不是就是l>r,那sort(arr,l,r); 进入函数不就直接退出了,因为l>r。不满足if(l<r)。这样都没法排序了都,不是吗
121楼 luyao07 2015-06-15 10:22发表 [回复]-
-
学长的解释太完美了,只是感觉挖坑添数还不够准确,应该是挖了新坑补旧坑,拆了东墙补西墙>.<
120楼 wyb_gg 2015-06-12 16:47发表 [回复]-
-
挖坑算法好牛逼,总算理解这个算法了!楼主机智啊
119楼 ChristXXX 2015-06-03 21:28发表 [回复]-
-
清楚明了! swap()函数很巧妙,改变基准同时使代码改动得很少
感谢
118楼 CutelittleBo 2015-06-03 08:43发表 [回复]-
-
终于看懂了,不容易啊~~~谢谢作者~
117楼 杨万榕 2015-06-01 22:15发表 [回复]-
-
第二次递归的时候,是不是错了?有点不能理解。
116楼 u010140778 2015-05-30 23:54发表 [回复]-
-
总算有个能看懂的了
115楼 junatxmu 2015-05-27 21:30发表 [回复]-
-
好赞好赞!
114楼 jxst602548 2015-05-27 07:46发表 [回复]-
-
看那么多文章,和数据结构书,都没你理解透彻,厉害
113楼 why的欢乐 2015-05-25 19:08发表 [回复]-
-
感觉太清楚了,代码也很易懂,好厉害。。。
112楼 yang1018679 2015-05-16 21:56发表 [回复]-
-
学习了。楼主辛苦!
111楼 Dablelv 2015-05-05 13:00发表 [回复]-
-
简单明了,受教了。
110楼 www060303 2015-04-27 16:27发表 [回复]-
-
讲的很好,一看就懂!
109楼 ruanbonan 2015-04-26 20:30发表 [回复]-
-
好文章,昨天研究了归并排序,谢!
108楼 读书点不浪漫 2015-04-17 22:36发表 [回复]-
-
数组大与10000的时候发生stackover floow 错误!
107楼 klower 2015-03-31 22:40发表 [回复]-
-
很清楚讲的...
106楼 xiyun0769 2015-03-31 15:23发表 [回复]-
-
看明白原理了,谢谢
105楼 evolone 2015-03-30 18:51发表 [回复]-
-
一看抬头就知道是师兄,感谢师兄写的文章,通俗易懂!赞一个!
104楼 tongxinhaonan 2015-03-26 20:03发表 [回复]-
-
楼主太牛了,一下子就看懂了
103楼 linshijun33 2015-03-22 20:47发表 [回复]-
-
谢谢师兄,明白快速排序算法是怎么回事了。
102楼 niuxiaobao 2015-03-17 23:44发表 [回复]-
-
谢谢!!!
101楼 倩影伊人 2015-03-16 13:13发表 [回复]-
-
“挖坑填数”,这个说法够形象,一看就明白,谢谢了!
100楼 zp007_enjoy 2015-03-16 10:01发表 [回复]-
-
简单明了地让人回忆起算法细节了,给赞!
99楼 o0Avalon0o 2015-03-14 19:23发表 [回复]-
-
特意登陆顶楼主
98楼 Mayqiyue 2015-03-12 21:29发表 [回复]-
-
楼组,我是特意注册账号来赞你的。原来看了这么多的讲解快排的,一直是懵懂不已,可是看了你的挖坑思想;我去,真是简单呀!瞬间不看实例代码就写出了快排!
97楼 Mayqiyue 2015-03-12 21:28发表 [回复]-
-
楼组,我是特意注册账号来赞你的。原来看了这么多的讲解快排的,一直是懵懂不已,可是看了你的挖坑思想;我去,真是简单呀!瞬间不看实例代码就写出了快排!
96楼 cherler 2015-03-07 13:22发表 [回复]-
-
“挖坑填数”果然简白易懂,攒!
Re: kindlyde 2015-04-15 12:18发表 [回复]-
-
回复chenwan1120:够形象。▁。
95楼 Lyfing 2015-03-03 12:18发表 [回复]-
-
谢谢楼主经典的“挖坑”思想。
94楼 little__student 2015-01-07 10:59发表 [回复]-
-
LZ的程序写的很好。有一点,"分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。" 楼主的程序表达的应该是将大于等于放到它的右边,小于它的数放到左边。而且,这个是与以左侧第一个数为枢纽元相符合的。
93楼 xiaolei_forever 2015-01-06 17:11发表 [回复]-
-
如果数列是 8,15,20 这样的应该如何写排序的步骤呢??? 望解答 是不是在查找的过程中比如i从左往右查找比基准数大的元素时不能越过基准数去基准数右侧查找,比如数列 7,2,5,11,6,14 基准数为11,谢谢
92楼 xiaolei_forever 2015-01-06 17:02发表 [回复]-
-
请问一下是不是开始时必须先j从右往左查找比基准数小的再i从左往右查找比基准数大的,然后依次循环?
91楼 charlieXavier 2014-12-30 15:13发表 [回复]-
-
一定要从右向左找比基准数小的数吗?可不可以从左开始找比基准数小的,从右向左找比基准数大的?试了试好像不行。。
90楼 sarah_cw 2014-12-22 10:40发表 [回复]-
-
楼主好厉害,终于明白了
89楼 雪海孤狼 2014-12-14 15:54发表 [回复]-
-
说什么呢! 非常感谢楼主的分享!
88楼 w1019187952 2014-11-30 09:23发表 [回复]-
-
爱死楼主了!!
87楼 doc6018 2014-11-19 17:37发表 [回复]-
-
学习了,以前看的都糊里糊涂,一看这个马上明白了。赞一个
86楼 qieman 2014-10-30 22:44发表 [回复]-
-
把博主的7中排序都用java写了遍,快排真是名副其实,哪怕只有10个数据快排也只是仅次于插排,大数据量更不用说明显比其他排序快,数据量上百万时堆排耗时约为快排2.5倍,归排约为快排1.5倍。
不过我对快排优化,递归到小于X时时采用插排,无论X怎么取在大于5000的数据量时效率都没什么提高,后来反复调试发现,当X设为20时,递归到len < X的时候len的分布很诡异,len的值集中在2和X-1两个端点,两者之间倒是挺均匀分布但挺少。
85楼 vbs100 2014-10-23 15:08发表 [回复]-
-
[cpp]
view plain
copy
- void quicksort(int s,int t,int a[])
- {
- int i=s,j=t,x=a[(i+j)/2],y;
- print2(a,s,t);
- do {
- while(a[i]<x)
- i++;
- while(a[j]>x)
- j--;
- if(i<=j)
- {
- y=a[j];
- a[j]=a[i];
- a[i]=y;
- i++;j--;
- }
- }while(i<j);
- if(j>s)
- quicksort(s,j,a);
- if(i<t)
- quicksort(i,t,a);
- }
这个更好理解一点
84楼 vbs100 2014-10-23 15:08发表 [回复]-
-
[cpp]
view plain
copy
- void quicksort(int s,int t,int a[])
- {
- int i=s,j=t,x=a[(i+j)/2],y;
- print2(a,s,t);
- do {
- while(a[i]<x)
- i++;
- while(a[j]>x)
- j--;
- if(i<=j)
- {
- y=a[j];
- a[j]=a[i];
- a[i]=y;
- i++;j--;
- }
- }while(i<j);
- if(j>s)
- quicksort(s,j,a);
- if(i<t)
- quicksort(i,t,a);
- }
这个更好理解一点
83楼 ice-frog 2014-10-18 19:25发表 [回复]-
-
看了这篇文章后,我不敢说这是最好的,但是它至少让我明白快速排序的原理。
谢谢楼主
82楼 张先森其实是张先生 2014-10-16 22:21发表 [回复]-
-
学习了,讲解浅显易懂。
81楼 mortimer7866 2014-10-05 15:54发表 [回复]-
-
写的不错,思路清晰,合并是亮点
80楼 liman65727 2014-09-29 16:56发表 [回复]-
-
楼主问一下:AdjustArray函数中while中if语句的作用是不是避免下次比较重复操作?
79楼 AsuraXG 2014-09-29 16:14发表 [回复]-
-
你好楼主,我想问一下为什么while里面要反复判断i<j?