5.快速排序。
以下代码可以从数组a[]中找出第k小的元素。
它使用了类似快速排序中的分治算法,期望时间复杂度是O(N)的。
请仔细阅读分析源码,填写划线部分缺失的内容。
题意:补全快速排序的算法。
分析:根据题意,就是找出数组中第k个元素,本题是想通过分治的原理进行查找,分治即是通过随机的某个数,将数组中比它大的换到右边,比它小的换到左边,再通过分别又一次的对左右边进行同样的处理,从而达到对数的排序。
根据下面这段代码,易知是要找到数组a中第5个元素。
#include <stdio.h>
int quick_select(int a[], int l, int r, int k) {
int p = rand() % (r - l + 1) + l;
int x = a[p]; //随机产生一个范围是【l,r】的p,并将a【p】的值赋给X
{int t = a[p]; a[p] = a[r]; a[r] = t;} //这里将a【p】与最后一个数交换,它为什么要这样做请看接下来的代码
int i = l, j = r; //首先把l和r赋值给i和j
while(i < j) { //程序用a【i】和a【j】分别从数组的两端向中间移动,每次的移动都会将比X小的数放在角标为i的地方,比X大的放在角标为j的地方
while(i < j && a[i] < x) i++; //首先是从头开始往后移动,找出比X大的数(这个数要放在后面)
if(i < j) { // 先进行第一次的分析,后面的循环分析是一样的
a[j] = a[i]; // 在进行第一次将前面比X大的数换到j的位置时,不用担心数组中最后一个元素被替换,因为X已经保存了这个元素
j--; //(而在后面几次这里的循环中你会发现这个值被替换前,这个值已经放到其它位置上了,所以不用担心有元素值没了)
} //在这一步我们也会发现最后面的元素已经被i所在的元素赋值了,而当前的i还存着应该放在后面的值,所以后面会把这个值替换
while(i < j && a[j] > x) j--; //从尾部往前走,找出比X大的值 放在i的位置,通过上面的步骤,你会发现那个i的值已经存放在别的地方
if(i < j) { //而我们也通过i保存比X小的数才是正常的,所以把后面的数赋值给a【i】
a[i] = a[j]; //然后进行同样的操作是一样的意思
i++; // 举个例子如49,38,27,13,65,76,97 如果p=2,X=27,那么将其换到最后面时就成了49,38,97,13,65,76,27, i=0,j=6
} //第一次操作从头比较时,当i=0时就数组就换成了49,38,97,13,65,76,49(x保存了27,所以不用担心!),然后j=5;
} //从后开始比较时,j=3时,13<27,所以放在i的地方,即取代49,变成13,38,97,13,65,76,49(后面是一样的)
a[i] = x; //通过上面的循环操作,就会发现最后i=j,同时i左边的数都比X小,i右边的数都比X大,最后把缺少的数(也就是X)放上去
p = i;
if(i - l + 1 == k) return a[i]; //如果满足条件,就说明这就是要找的数所以直接返回这个值
if(i - l + 1 < k) return quick_select( _______a,i+1,r,k-(i-l+1)______________________ ); //填空
else return quick_select(a, l, i - 1, k); //通过分析i-l+1 和k 的大小来进行选择操作,。如果因为此时i的值大小就是这个值在排序后的位置
} //选择操作:如果i-l+1比k大,那就说明k所代表的值在左边,否则就在右边,然后再进行重复的递归操作
int main()
{
int a[] = {1, 4, 2, 8, 5, 7, 23, 58, 16, 27, 55, 13, 26, 24, 12};
printf("%d\n", quick_select(a, 0, 14, 5));
return 0;
}
————————————————
版权声明:本文为CSDN博主「JXUFE_ACMer」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jxufe_acmer/article/details/80157470