C++程序 在数据流中查找第k大元素
在处理数据流时,假如需要找到其中第k大的元素,可以使用优先队列(Priority Queue)来处理。在C++中,标准库STL提供了Priority Queue的实现。
什么是Priority Queue
Priority Queue是一种通过 堆(Heap) 来实现的数据结构,它遵循以下规则:
- 它是一个有序的序列,每个元素有自己的权值。
- 在Priority Queue中,权值最大的元素永远排在最前面(因此也叫最大堆),而权值较小的元素则排在后面。
- 当在Priority Queue中插入一个新的元素时,它会自动排序,使得新的元素插入到合适的位置。
- 删除Priority Queue中的元素时,它会自动将最大权值的元素弹出(也就是先进先出)。
优先队列的用法
在C++中,Priority Queue的定义如下:
template<
class T,
class Container = std::vector<T>,
class Compare = std::less<typename Container::value_type>
> class priority_queue;
其中,T为Priority Queue中元素的类型,Container则是底层的容器类型,而Compare则是元素间比较的方式。如果不指定Compare,则默认使用std::less。
接下来,我们给出一个简单的例子,演示了在数据流中查找第k大元素的实现方法。
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
class KthLargest {
public:
KthLargest(int k, vector<int>& nums) {
m_k = k;
for(auto n : nums) {
add(n);
}
}
int add(int val) {
if(m_queue.size() < m_k) {
m_queue.push(val);
} else if(val > m_queue.top()) {
m_queue.pop();
m_queue.push(val);
}
return m_queue.top();
}
private:
priority_queue<int, vector<int>, greater<int>> m_queue;
int m_k;
};
int main() {
int k = 3;
vector<int> nums = {4, 5, 8, 2};
KthLargest kthLargest(3, nums);
cout << kthLargest.add(3) << endl; // 返回 4
cout << kthLargest.add(5) << endl; // 返回 5
cout << kthLargest.add(10) << endl; // 返回 5
cout << kthLargest.add(9) << endl; // 返回 8
cout << kthLargest.add(4) << endl; // 返回 8
return 0;
}
在上述例子中,我们定义了一个类KthLargest用于在数据流中查找第k大的元素。类的构造函数中,初始化了m_k表示需要查找的元素的下标,同时通过for循环将nums中的元素依次加入到Priority Queue中。在add函数的实现中,我们采用了以下方法:
- 如果Priority Queue的大小小于k,直接将元素加入到Priority Queue中。
- 如果Priority Queue的大小等于k,将新元素和Priority Queue中的最小元素进行比较。
- 如果新元素较大,将Priority Queue中的最小元素弹出,将新元素加入到Priority Queue中。
- 如果新元素较小,不进行操作,直接返回Priority Queue中的最小元素。
最终,在main函数中测试时,我们得到了正确的结果。完整的代码可以在本文末尾的github链接查看。
时间复杂度和空间复杂度
在Priority Queue的实现过程中,我们使用到了堆(Heap)的数据结构,每次插入和弹出元素的时间复杂度为O(logN),其中N为Priority Queue中元素的个数。在构造函数中,我们需要将所有元素遍历一遍,因此时间复杂度为O(NlogK),其中K为需要查找的元素的下标。所以,总的时间复杂度为O(NlogK)。
在空间复杂度方面,我们需要使用一个Priority Queue来存储元素,因此空间复杂度为O(K)。
结论
在处理数据流时需要查找第k大的元素,可以使用Priority Queue来实现。在将元素加入Priority Queue时,可以使用类似于快速排序的方法,将小于等于第k大元素的元素都弹出,只保留大于第k大元素的元素。通过这种方式,可以保证Priority Queue中存储的都是大于第k大元素的元素,最后返回Priority Queue中的最小元素即可。在时间复杂度方面,总的时间复杂度为O(NlogK),空间复杂度为O(K)。