寻找n个数的第K项只需要对它们进行排序,然后找到即可。但是耗时O(nlongn);在书上看到了很好的方法,想着实现一下:
输入:一个数列A,一个整数K
输出:数列A中第K小的数
我们假定数组的一个数V,现在把数组A分成三份。{
A1 = { X | X < V }
A2 = { X | X = V }
A3= { X | X > V }
}
例如任意一个数组A={2,36,5,21,8,13,11,20,5,4,1};
假设V等于5 A1=2 4 1 ; A2=5 5; A3=36 21 8 13 11 20
搜索范围就减小了。现在只需要在A的三个子集中寻找,如果想寻找第8小元素,他一定在A3中,同理可以得到递归
f(A1,v) if k<=|A1|
f(A,k)= printf(A2) if k==|A1+A2|
f(A3,v-|A1|-|A2|) if k>|A1+A2|
思路清晰后,重要的是V的选取,因为V的选取决定了整个算法的复杂度。最理想的情况就是|A1|,|A3|=1/2|A|
如果我们一直背运,我们选出来的V很可能一直是数组的最大元素或者最小元素,那么算法需要执行
n+(n-1)+(n-2)+....+n/2=O(n*n)
但是这种情况出现的概率非常低
最好的情形是选取的V正好能把数组一分为二,从而复杂度为O(n)
从O(n)->O(n*n) 算法的平均运行时间基本符合最佳运行时间
当然代码肯定有瑕疵。才接触分治 又不好的地方大家一起交流下
#include<cstdio>
#include<iostream>
using namespace std;
void f(int a[], int zuo, int you, int v){
//printf("%d\n", v);
//for (int i = zuo; i <= you; i++){
// printf("%d ", a[i]);
//}
//system("pause");
//printf("\n");
int a1[10] = { 0 }, a2[10] = { 0 }, a3[10] = {0};
int num = v / 2;
int j = 0, k = 0, l = 0;
for (int i = zuo; i <= you; i++){
if (a[i] < a[num])
a1[j++] = a[i];
else if (a[i] == a[num])
a2[k++] = a[i];
else
a3[l++] = a[i];
}
if (v <= j){
f(a1, 0, j - 1, v);
}
else if (v>j&&v<=k+j) {
printf("%d ", a2[k-1]);
return;
}
else if (v > j + k){
f(a3, 0, l - 1, v - j - k);
}
}
int main(){
int a[10] = { 1, 3, 5, 2, 4, 6, 7, 8 };
int b[10] = { 1, 3, 9, 5, 2, 4, 6, 7, 8 };
//int n = 8;
int k;
//scanf("%d", &k);
printf("偶数的第n小的值分别为:\n");
for (int k = 1; k <= 8;k++)
f(a, 0, 7,k);
printf("\n奇数的第n小的值分别为:\n");
for (int k = 1; k <= 9; k++)
f(b, 0, 8, k);
return 0;
}