算法导论例程——快速排序

来源:互联网 发布:开淘宝网店注册收费 编辑:程序博客网 时间:2024/06/05 04:55

快速排序是一种最坏情况复杂度为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]交换。

#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;}}





0 0
原创粉丝点击