排序,前K大问题
1. 方法描述
- 我的想法是利用数组存储所有元素(下标为1~n),通过堆排序来实现排序功能,因为我们可以通过堆排序,每次得到第N大元素(N指的是次数),初始的大顶堆第i次会将最大的元素移到第n-i+1个位置(我最初的想法是冒泡排序,因为它会将第i大的元素冒到第n-i+1的位置,但是时间复杂度和空间复杂度较高);
2. 预估的时间复杂度和空间复杂度
- 时间复杂度:O(Klogn),我觉得它要进行K-1次的筛选调整和交换,而每次的时间复杂度为O(logn);
- 空间复杂度:O(1),辅助存储空间如temp等与n无关;
3. 伪代码
-
void HeapSort(Rectype s[], int n, int K) { int i; 得到初始堆; 进行K - 1次交换和sift算法; } void sift(Rectype s[], int low, int high) { int i = low, j = i * 2; Rectype temp = s[i];//得到堆的堆顶 while (j <= high) {//调整堆顶元素位置 if (j < high && s[j] < s[j + 1]) { j++;//找堆顶的最大孩子 } if (堆顶小于它最大的孩子) { 孩子调整到双亲节点; 向下筛选调整; } else { break;//无需继续筛选调整 } } s[i] = temp;//堆顶元素找到合适位置 }
4. 代码
-
初步代码(思路来源于书本和ppt)
#include <iostream> #define N 100001 typedef int Rectype; using namespace std; Rectype s[N]; void swap(int& a, int& b) { int temp = b; b = a; a = temp; } void sift(Rectype s[], int low, int high) { int i = low, j = i * 2; Rectype temp = s[i]; while (j <= high) { if (j < high && s[j] < s[j + 1]) { j++; } if (temp < s[j]) { s[i] = s[j]; i = j; j = 2 * i;//向下筛选 } else { break; } } s[i] = temp; } void HeapSort(Rectype s[], int n,int K) { int i; for (i = n / 2; i >= 1; i--) { sift(s, i, n);//从下往上调整 } for (i = n; i >= n - K + 1; i--) { swap(s[1], s[i]); sift(s, 1, i - 1); } } int main() { int i, n; cin >> n; for (i = 1; i <= n; i++) { cin >> s[i]; } int K; cin >> K; if (n < K) { cout << "超出范围,无法得到前K大的数"; } else { HeapSort(s, n, K); for (i = n; i >= n - K + 1; i--) { if (i == n) { cout << s[i]; } else { cout << " " << s[i]; } } } return 0; }