快速排序_泰山鲁用村里抢媳妇的故事说明这个算法
2016-07-16 19:27
281 查看
复杂度是 O(N*logN)。
快速排序没有冒泡那么容易,但是可以快速搞定排序。
快速排序是一种划分交换排序。它采用了分治的策略,通常称其为分治法。
该方法的基本思想是:【沿用经典老前辈的总结】
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
百度的专业里把这个算法讲的云里雾里其实很简单:我这沿用网上的专词 叫挖坑,泰山鲁言:这就好比去别人家偷老婆的一个过程,自己老婆被挖走了,就去别人窝里偷。找到满意的花姑娘,抱上就藏到自己屋。别人家就成空房了,被偷那家为了防止晚上饥渴,就去偷其他家里的来圆房,偷到后被偷的另外又一家的屋里又少了媳妇,又成了一个坑。我们把村里第一个丢的姑娘也就是称为基准值的那个姑娘称为基准姑娘,由于挑选条件规律是,从前面搜的人要找比基准姑娘丑的姑娘,从后面搜的人要找比基准姑娘漂亮的姑娘
这样一趟倒腾下来,那个基准姑娘就停留在了村里全村女人都参与的选美大赛中合适的位置。
这个女人定位后,其他趟就可以不管他了,剩下的女人比这个姑娘丑的前面一堆 自己堆里再来此比较,比这个姑娘漂亮的堆里再自己来一次比较。就这样不断分割,最后大家都再各自的位置上,而且每个人也都有媳妇。有序不说,每个坑都有媳妇,社会也和谐了。
先沿用教材中的实例吧
泰山鲁言: 规律就是,自己丢了媳妇的汉子,去别家抢,前面找找,后面找找,找到之后,后放到屋里,(抓别人的媳妇,送自己窝去,因为自己的媳妇被前面的兄弟抓走了),同时被抢的哥们家里没媳妇了又成一个坑了,他就要去找别的媳妇圆填自己的坑了,从前面找的找小于等于首选数的,从后面找的找大于首选数的。由于一般算法都爱把0元素先挖出来,(完恶之本,自己家就空了,去偷别人的媳妇,偷完别人家空了,就又偷其他家的媳妇,闹的整个村就乱了)。
初始时,i = 0; j = 9; X = a[i] = 72
第一炮不比较结果直接把a[0]挖出去,同时直接形成新坑,(完恶之本,屋里缺人就开始去别人家抢了),同时将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--;
(村里乱了,你抢我老婆,我去抢其他人的老婆)
数组变为:
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]。(最后个人没媳妇可偷了,这个时候,失踪多日的基准姑娘,回来了也发现自己没窝睡,就填充上了)
数组变为:
可以看出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]中。
照着这个总结很容易实现挖坑填数的代码:
代码写的其实不怎么好甚至很烂,我也懒得改了,道理讲明白,大家可以自己试验试验看,看懂就行,在项目中尽量不要自己去写底层算法,又笨又慢,还容易惹祸,研究研究就好
[cpp] view
plain copy
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;
}
再写分治法的代码:
[cpp] view
plain copy
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);
}
}
这样的代码显然不够简洁,对其组合整理下:
[cpp] view
plain copy
//快速排序
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.先从数列中取出一个数作为基准数。
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]挖出去,同时直接形成新坑,(完恶之本,屋里缺人就开始去别人家抢了),同时将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 |
再重复上面的步骤,先从后向前找,再从前向后找。
从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 |
[引用前辈对这个算法的总结]
对挖坑填数进行总结
1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。
2.j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。
3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。
4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。
照着这个总结很容易实现挖坑填数的代码:
代码写的其实不怎么好甚至很烂,我也懒得改了,道理讲明白,大家可以自己试验试验看,看懂就行,在项目中尽量不要自己去写底层算法,又笨又慢,还容易惹祸,研究研究就好
[cpp] view
plain copy
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;
}
再写分治法的代码:
[cpp] view
plain copy
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);
}
}
这样的代码显然不够简洁,对其组合整理下:
[cpp] view
plain copy
//快速排序
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);
}
}
相关文章推荐
- 16. 3Sum Closest
- ROS学习之 roslaunch
- 【字符串】C++字符串编程小结
- 已知一对夫妇有两个孩子,如果知道有一个是男孩,那么两个都是男孩的概率?
- HDU 5319 Painter(暴力枚举)
- 通讯录
- BigInteger和BigDecimal大数相加问题
- 解决git error: failed to push some refs to 'git@github.com:
- Codeforces 607B Zuma(区间DP)
- Android属性动画完全解析
- 指针知识点
- MySql 64位 windows下环境配置
- Hashtable类源码解析
- Vim基础操作
- 关于网络流sap算法
- 15. 3Sum
- tomcat篇之tomcat结合apache中的模块proxy反代理之apache安装
- IDEA没有代码提示的可能原因
- Apache服务器运维笔记(6)----目录 文件 网络容器的安全问题
- 已知n阶矩阵A的行列式满足|A|=1,求|A^(-1)|(A^(-1)表示A的逆矩阵)=?