算法导论例程——快速排序
2016-02-05 20:37
351 查看
快速排序是一种最坏情况复杂度为o(n^2),平均时间复杂度为o(nlgn)的排序算法,且nlgn隐含的常数因子非常小,最坏情况发生的概率也不高,进行的是原址排序,所以是采用度最高的一种排序算法,在c++的stdlib库中特别封装了qsort函数方便用户使用。
快速排序是冒泡排序的一种升级版本,主要思想就是选择数组中的一个值作为关键字(key),将数组中所有比key小的放在key前,比key大的放在key后,之后再对a[0,...key-1]和a[key+1,...end]递归地使用qsort过程,直到数组规模为1为止,这样就保证整个数组都是有序的了。
在实际过程中,一般选取数组最后一位作为key值,最初时将i的值选在数组外,之后遍历数组a[start,...,key-1],以i作为分界点,比key小的放在i左侧,大的放在i右侧,最后把a[key]与a[i]交换。
以上这种选key的方式也有一定局限性,当输入的恰好是升序时,每次分成的两个部分都是0和n-1,这样就会是运行时间达到o(n^2),改进的办法是用随机数法找到一个key值,这样就能保证每次选取都处于一种平均情况。
而对于原来的函数,我们可以很清楚地看出这是一个尾递归,由于递归对系统产生的额外开销(参数入栈 返回地址入栈 保存现场 进入子函数 返回地址出栈 恢复现场 ),我们应尽量减少递归的部分,因此做以下改写。
快速排序是冒泡排序的一种升级版本,主要思想就是选择数组中的一个值作为关键字(key),将数组中所有比key小的放在key前,比key大的放在key后,之后再对a[0,...key-1]和a[key+1,...end]递归地使用qsort过程,直到数组规模为1为止,这样就保证整个数组都是有序的了。
在实际过程中,一般选取数组最后一位作为key值,最初时将i的值选在数组外,之后遍历数组a[start,...,key-1],以i作为分界点,比key小的放在i左侧,大的放在i右侧,最后把a[key]与a[i]交换。
#include <stdio.h> void qsort(int a[], int start, int end); int divide(int a[], int start, int end); int main() { int a[1000] = { 0 }, i = 0, n = 0, length = 0; printf("请输入要排序的数组规模:"); scanf("%d", &n); length = n; while (n--) scanf("%d", &a[i++]); qsort(a, 0, length - 1); i = 0; while (length--) printf("%d,", a[i++]); return 0; } void qsort(int a[], int start, int end) { int key; if (start < end) { key = divide(a, start, end); qsort(a, start, key - 1); qsort(a, key + 1, end); } } int divide(int a[], int start, int end) { int key = 0, i = 0, j = 0,temp = 0; key = a[end]; i = start - 1; for (j = start; j < end; j++) { if (a[j] <= key) { i++; temp = a[i]; a[i] = a[j]; a[j] = temp; } } i++; temp = a[i]; a[i] = a[end]; a[end] = temp; return i; }要注意的是在交换值得时候不要写成下面这个样子,当i == j时会出现错误(变动的是同一个位置的数,最后就变成0了)
以上这种选key的方式也有一定局限性,当输入的恰好是升序时,每次分成的两个部分都是0和n-1,这样就会是运行时间达到o(n^2),改进的办法是用随机数法找到一个key值,这样就能保证每次选取都处于一种平均情况。
#include <stdio.h> #include <stdlib.h> #include <time.h> void qsort(int a[], int start, int end); int divide(int a[], int start, int end); int main() { int a[1000] = { 0 }, i = 0, n = 0, length = 0; printf("请输入要排序的数组规模:"); scanf("%d", &n); length = n; while (n--) scanf("%d", &a[i++]); qsort(a, 0, length - 1); i = 0; while (length--) printf("%d,", a[i++]); return 0; } void qsort(int a[], int start, int end) { int key; if (start < end) { key = divide(a, start, end); qsort(a, start, key - 1); qsort(a, key + 1, end); } } int divide(int a[], int start, int end) { int key = 0, i = 0, j = 0, temp = 0, ran = 0; srand((unsigned)time(NULL)); ran = start + rand() % (end - start); //注意范围 key = a[ran]; temp = a[end]; a[end] = a[ran]; a[ran] = temp; i = start - 1; for (j = start; j < end; j++) { if (a[j] <= key) { i++; temp = a[i]; a[i] = a[j]; a[j] = temp; } } i++; temp = a[i]; a[i] = a[end]; a[end] = temp; return i; }对于随机数法,还有一种更加细致地找到key值得方法——三数取中法,就是随机生成满足条件的三个数,之后取他们的中位数作为key值,这样选取对于样本来说更为“均衡”。
而对于原来的函数,我们可以很清楚地看出这是一个尾递归,由于递归对系统产生的额外开销(参数入栈 返回地址入栈 保存现场 进入子函数 返回地址出栈 恢复现场 ),我们应尽量减少递归的部分,因此做以下改写。
void tail_qsort(int a[], int start, int end) { int q; while (start < end) { q = divide(a, start, end); tail_qsort(a, start, q - 1); p = q + 1; } }
相关文章推荐
- 【jQuery基础学习】11 jQuery性能简单优化
- 小蚂蚁学习数据结构(30)——图的其他知识点简介
- bootstrap之WaitForIdle&&Clear
- 关于SAE没有file_put_contents写权限的问题
- POJ 1922:Ride to School 【水】
- 快速排序
- matlab BP神经网络 机器学习 函数逼近
- Codeblocks如何调试DLL
- HDU 2151 Worm (动态规划)
- zoj 1221 Risk【最短路 3种方法】
- nyoj458小光棍数
- poj3254 Corn Fields
- ecshop 微信支付插件
- Mybatis 的日志管理
- 微信后台数据服务器
- ubuntu亮度调节失效
- codeforces AIM Tech Round
- HDU 4612 Warm up(边双连通分量)
- IIyarrAdetroSmorfsetacilpuDevomeR.80
- pcm2076最好的外置声卡芯片