参考:https://blog.csdn.net/njust_ecjtu/article/details/27491573
此题第一思路肯定是,排序后,直接输出,但是时间复杂 度O(nlgn);那么有没有更快的呢?答案是肯定的。
在我们将利用快排的划分法进行。其中的思路可参见算法导论120页,具体证明步骤也有。具体代码在下面:
再者此题也适合求最小的k个数,最大的k个数(只不过相当于求n-k个小的数,在转化下)。
把此题归类为线性查找算法!
- #include <iostream>
- #include <cassert>
- using namespace std;
- int partition(int *A,int s,int e);//划分
- int select_k(int * A,int n,int k);
- int select_k_recursive(int * A,int s,int e,int k);//选出第k个大的数
- int main()
- {
- int A[10] = {3,2,6,4,9,8,7,1,5,0};
- //下标!
- cout<<select_k(A,10,3)<<endl ;
- return 0;
- }
- int select_k(int * A,int n,int k)//选出第k个小的数
- {
- assert(A&& n > 0&& k <= n);
- return select_k_recursive(A,0,n-1,k);//只需输出前k个元素即可,即最小的k个
- }
- int select_k_recursive(int * A,int s,int e,int k)
- {
- if (s == e)
- {
- return A[s];
- }
- int index = partition(A,s,e);
- if (index == k-1)//此处为第k个转化为下标为k-1
- {
- return A[index];
- }
- else if(index > k-1)
- {
- return select_k_recursive(A,s,index-1,k);// 大于则,在左边
- }
- else
- {
- return select_k_recursive(A,index+1,e,k);//小于则,在右边
- }
- }
- int partition(int *A,int s,int e)//快排中的划分
- {
- assert(A&& s <= e);
- int pivot = A[s];
- while(s < e)
- {
- while(s < e&&A[e] > pivot)e--;
- A[s] = A[e];
- while(s < e&&A[s] < pivot)s++;
- A[e] = A[s];
- }
- A[s] = pivot;
- return s;
- }
(输出前k小的所有元素。初始版本,后期会优化,也望读者批评指正。后期我会并更新其他关联问题)
#include <iostream>
#include <cassert>
using namespace std;
int partition(int *A, int s, int e);//划分
int select_k(int * A, int n, int k);
int select_k_recursive(int * A, int s, int e, int k);//选出第k个大的数
void main()
{
int A[10] = {3,5,1,4,2,9,6,7,8,10};
//下标!
select_k(A, 10,7);
//cout << A[0] << " " << A[1] << " " << A[2] << " " << A[3] << " " << A[4] << " " << endl;
//return 0;
}
int select_k(int * A, int n, int k)//选出第k个小的数
{
assert(A&& n > 0 && k <= n);
select_k_recursive(A, 0, n - 1, k);//只需输出前k个元素即可,即最小的k个
return 0;
}
int select_k_recursive(int * A, int s, int e, int k)
{
if (s == e)
{
return A[s];
}
int index = partition(A, s, e);
if (index == k - 1)//此处为第k个转化为下标为k-1
{
cout << "前k小的数是:";
for (int p = 0; p <= index; ++p) //利用了快速排序每次划分结束后返回s,A[s]左边永远小于A[s]
//右边永远大于A[s]
{
cout << A[p] << " ";
}
cout << endl;
//return A[index];
return 0;
}
else if (index > k - 1)
{
return select_k_recursive(A, s, index - 1, k);// 大于则,在左边
}
else
{
return select_k_recursive(A, index + 1, e, k);//小于则,在右边
}
}
int partition(int *A, int s, int e)//快排中的划分 s左边数都比A[s]大,右边的都比A[s]小
{
assert(A&& s <= e);
int pivot = A[s];
while (s < e)
{
while (s < e&&A[e] > pivot)e--;
A[s] = A[e];
while (s < e&&A[s] < pivot)s++;
A[e] = A[s];
}
A[s] = pivot;
return s;
}
注意这个输出,数组顺序已经被打乱,我会更新不改变输入数组的算法实现
转载需要私信博主征得同意,并指定出处:https://blog.csdn.net/qq_34793133/article/details/80607743
未经博主允许不得转载