求前K个最大的数(排序问题)
- 问题:g给出无序序列,求前k大(小)的数,或求第k大(小)的数。
- 分析:
- 1、利用快排的思想 : 快速排序每一轮其实将左右两个子序列排好序(分割点后序列中的所有数字均大于分割点前的所有数字)如果分割点是K那么很容易得到前k大(小)的数字。时间复杂o(n)
- 2、堆排序,可以直接找到前K个最大的数即可。堆排序重要操作:1、堆调整(基于大顶堆或小顶堆调整),2、基于堆调整进行建堆 3、将对顶元素删除,并使用最后一个叶节点的元素覆盖堆顶 4、进行堆调整,5、反复进行3,、4步,直到堆中还剩k个元素。
- 代码2(堆排序)
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include<assert.h>
void AdjustDown(int* a, int parent, int size)
{
int child = 2 * parent + 1;
while (child < size)
{
if (child + 1 < size && a[child] > a[child + 1])
{
child++;
}
if (a[parent]>a[child])
{
swap(a[parent], a[child]);
parent = child;
child = 2 * parent + 1;
}
else
{
break;
}
}
}
void Print(int* a, int size)
{
cout << "前k个最大的数据:" << endl;
for (int i = 0; i < size; i++)
{
cout << a[i] << " ";
}
cout << endl;
}
int* HeapSet(int*a,int N,int K)
{
assert(a);
assert(K > 0);
int* arr = new int[K];
//将前K个数据保存
for (int i = 0; i < K; i++)
{
arr[i] = a[i];
}
//建堆
for (int i = (K-2)/2; i >=0; i--)
{
AdjustDown(arr,i,K);
}
//对剩余的N-K个元素比较大小
for (int i = K; i < N; i++)
{
if (arr[0]<a[i])
{
arr[0] = a[i];
AdjustDown(arr, 0, K);
}
}
return arr;
delete[] arr;
}
void Test()
{
int arr[] = { 12, 2, 10, 4, 6, 8, 54, 67, 25, 178 };
int k = 5;
int* ret = HeapSet(arr, sizeof(arr) / sizeof(arr[0]), k);
Print(ret, k);
}
int main()
{
Test();
system("pause");
return 0;
}
int Partition(vector<int> &v, int head, int rear){
int key = v[head];
while (head < rear){
while (v[rear] <= key && head < rear){
--rear;
}
swap(v[head], v[rear]);
while (v[head] >= key && head < rear){
++head;
}
swap(v[rear], v[head]);
}
v[head] = key;
++my_count;
return head;
}
int QuickSearch(vector<int> &v, int head, int rear, int k){
int pivot = -1, len = 0;
if (head < rear){
pivot = Partition(v, head, rear);
len = pivot - head + 1;
if (len < k){
pivot = QuickSearch(v, pivot + 1, rear, k - len);
}
else if (len > k){
pivot = QuickSearch(v, head, pivot - 1, k);
}
}
return pivot;
}