话不多说,直接上代码
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;
void swap(int a[], int i, int j)
{
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
int partition(int a[], int left, int right)
{
// 设置随机种子
srand(time(NULL));
int x = rand();
// 随机哨兵位置
x = (x % (right - left + 1)) + left;
swap(a, left, x);
int tmp = a[left];
int i = left + 1;
int j = right;
while (true) {
// 左侧通过小于哨兵的值
while (a[i] < tmp && i < right) {
i ++;
}
// 右侧通过大于哨兵的值
while (a[j] > tmp && j > 0) {
j --;
}
// 未通过的左右值交换
if (i < j) {
swap(a, i, j);
} else {
// 已经完成划分,返回切分点,由于哨兵当前位于左侧,因此和错位的j交换
swap(a, left, j);
return j;
}
}
}
// 取最大k个
void topk(int a[], int left, int right, int k)
{
int p = partition(a, left, right);
int width = right - p;
if (width == k || (width + 1) == k) {
return;
} else if (width > k) {
topk(a, p + 1, right, k);
} else {
topk(a, left, p, k - width);
}
}
// 取最小k个
void bottomk(int a[], int left, int right, int k)
{
int p = partition(a, left, right);
// 左侧宽度
int width = p - left;
// 划分结果刚好合适
if (width == k || (width + 1) == k) {
return;
// 切分不够细,继续划分左侧
} else if (width > k) {
bottomk(a, left, p - 1, k);
// 左侧数据不够多,从右侧分
} else {
bottomk(a, p, right, k - width);
}
}
void output(int a[], int n)
{
for (int i = 0; i < n; i ++) {
cout << a[i] << ",";
}
cout << endl;
}
int main()
{
// 测试数据
const int n = 8;
int nums1[n] = {4,5,3,2,8,6,9,0};
int k = 2;
topk(nums1, 0, n - 1, k);
cout << "top" << k << endl;
output(nums1, n);
int nums2[n] = {4,5,3,2,8,6,9,0};
bottomk(nums2, 0, n - 1, k);
cout << "bottom" << k << endl;
output(nums2, n);
return 0;
}