无序数组中找第K大的数_落花逐流水的博客_无序数组找k大

类快排算法

leetcode215

由于只要求找出第k大的数,没必要将数组中所有值都排序。

典型解法:快速排序分组。

在数组中找到第k大的元素 取基准元素,将元素分为两个集合,一个集合元素比基准小,另一个比基准大 ,三种情况。 1.比基准大的元素数目标志位m正好为k-1,基准就是目的元素。 2.比基准大的元素标志位m小于k, 那么就在比基准小的集合里面找第(k-m)大的元素 3.若是比基准大的元素为m大于k,那就继续在该集合里面找第k大的元素。

快排中的partition算法,返回key在数组中的位置的cnt(相对于left的偏移量),如果cnt正好等于k,那么问题则得到解决;如果cnt小于k,去左边找第k个;如果cnt>k,则去右边找第k-cnt个。直到key的位置等于k-1,则找对问题的解。

 
  1. /*快排中的划分算法*/

  2. int partition(int* input, int low, int high)

  3. {

  4. int tmp = input[low]; // 取一个基准元素

  5. while (low < high) {

  6. while (low < high && input[high] <= tmp) {

  7. high--;

  8. }

  9. input[low] = input[high];

  10. while (low < high && input[low] >= tmp) {

  11. low++;

  12. }

  13. input[high] = input[low];

  14. }

  15. input[low] = tmp;

  16. return low;

  17. }

  18. // 参数left需要小于right

  19. int findK(int* array, int left, int right, int k) {

  20. //printf("%d %d %d\n", left, right, k);

  21. int i = partition(array, left, right);

  22. int cnt = i - left + 1;

  23. if (k == cnt) {

  24. return array[i];

  25. } else if (k < cnt) {

  26. return findK(array, left, i - 1, k);

  27. } else if (k > cnt) {

  28. return findK(array, i + 1, right, k-cnt);

  29. }

  30. return 0;

  31. }

此解法的时间复杂度为O(N*lgK),logK次每次O(N),优于排序解法.

测试程序:

 
  1. #include <iostream>

  2. #include <vector>

  3. using namespace std;

  4. /*快排中的划分算法*/

  5. int partition(int* input, int low, int high)

  6. {

  7. int tmp = input[low]; // 取一个基准元素

  8. while (low < high) {

  9. while (low < high && input[high] <= tmp) {

  10. high--;

  11. }

  12. input[low] = input[high];

  13. while (low < high && input[low] >= tmp) {

  14. low++;

  15. }

  16. input[high] = input[low];

  17. }

  18. input[low] = tmp;

  19. return low;

  20. }

  21. // 这里得到的是第k小,自己n-k转换下即可, 或者改下划分函数

  22. int findK(int* array, int left, int right, int k) {

  23. //printf("%d %d %d\n", left, right, k);

  24. int i = partition(array, left, right);

  25. int cnt = i - left + 1;

  26. if (k == cnt) {

  27. return array[i];

  28. }

  29. else if (k < cnt) {

  30. return findK(array, left, i - 1, k);

  31. }

  32. else if (k > cnt) {

  33. return findK(array, i + 1, right, k - cnt);

  34. }

  35. return 0;

  36. }

  37. int main()

  38. {

  39. vector<int> ilist = {9, 5, 8, 7, 3, 6, 2, 1, 4, 0};

  40. int arr[10];

  41. int n = ilist.size();

  42. std::copy(ilist.begin(), ilist.end(), arr);

  43. int k = 3;

  44. int num = findK(arr, 0, n-1, k);

  45. cout << num << endl;

  46. system("pause");

  47. return 0;

  48. }

快排加二分查找:

 
  1. int a[]={7,9,8,5,6,3,2,4,1,0};

  2. const int K=6;

  3. //解题思路就是利用快速排序,如果得到快速排序一次中间结果之后其所在位置即在

  4. int QSort(int* a,int low,int high)

  5. {

  6. if(low<high)

  7. {

  8. int start=low,end=high;

  9. int key=a[start];

  10. while(start<end)

  11. {

  12. while(start<end&&a[end]<key)

  13. {

  14. end--;

  15. }

  16. a[start]=a[end];

  17. while(start<end&&a[start]>key)

  18. {

  19. start++;

  20. }

  21. a[end]=a[start];

  22. }

  23. a[start]=key;

  24. return start;

  25. }

  26. return -1;

  27. }

  28. int main()

  29. {

  30. int start=0,end=sizeof(a)/sizeof(int)-1;

  31. int index=-2;

  32. while(index+1!=K)

  33. {

  34. index=QSort(a,start,end);

  35. if(index<K)

  36. {

  37. start=index+1;

  38. }

  39. else if(index>K)

  40. {

  41. end=index-1;

  42. }

  43. }

  44. cout<<a[index]<<"即为所求\n";

  45. }

最小堆解法

构造一个大小为k的最小堆,堆中根节点为最小值。如果数组中最大的几个数均在堆中,那么堆中根节点的值就是问题的解。

可以用STL中的优先队列实现,因为优先队列的内部就是最大堆/最小堆实现的。

此解法的时间复杂度O(NlogK),N次logK。但是相比与类快速排序算法,需要额外的存储空间。

 
  1. #include <iostream>

  2. #include <vector>

  3. using namespace std;

  4. void maxHeapify(int* array, int size, int i) {

  5. int left = 2 * i + 1;

  6. int right = 2 * i + 2;

  7. int small = i;

  8. if (left < size) {

  9. if (array[small] > array[left]) {

  10. small = left;

  11. }

  12. }

  13. if (right < size) {

  14. if (array[small] > array[right]) {

  15. small = right;

  16. }

  17. }

  18. if (small != i) {

  19. int temp = array[small];

  20. array[small] = array[i];

  21. array[i] = temp;

  22. maxHeapify(array, size, small);

  23. }

  24. }

  25. void buildHeap(int* array, int size) {

  26. for (int i = size - 1; i >= 0; i--) {

  27. maxHeapify(array, size, i);

  28. }

  29. }

  30. int findKByHeap(int* array, int n, int k) {

  31. buildHeap(array, k);

  32. for (int i = k; i < n; i++) {

  33. if (array[i] > array[0]) {

  34. int temp = array[i];

  35. array[i] = array[0];

  36. array[0] = temp;

  37. maxHeapify(array, k, 0);

  38. }

  39. }

  40. return array[0];

  41. }

  42. int main()

  43. {

  44. vector<int> ilist = {9, 5, 8, 7, 3, 6, 2, 1, 4, 0};

  45. int arr[10];

  46. int n = ilist.size();

  47. std::copy(ilist.begin(), ilist.end(), arr);

  48. int k = 5;

  49. int num = findKByHeap(arr, n, k);

  50. cout << num << endl;

  51. system("pause");

  52. return 0;

  53. }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值