1.stack 先进后出
1.1常见函数 :top empty size push pop
2.queue 先进先出
2.1常见函数 :front back empty size push pop
3.Deque
在C++中,deque
容器(双端队列)提供了许多成员函数,用于在双端队列中插入、删除、访问和操作元素。下面是一些deque
常见的函数:
-
push_back()
:将元素插入双端队列的末尾。 -
push_front()
:将元素插入双端队列的开头。 -
pop_back()
:从双端队列的末尾删除一个元素。 -
pop_front()
:从双端队列的开头删除一个元素。 -
size()
:返回双端队列中元素的个数。 -
empty()
:检查双端队列是否为空。 -
clear()
:删除双端队列中的所有元素。 -
back()
:返回双端队列中的最后一个元素的引用。 -
front()
:返回双端队列中的第一个元素的引用。 -
at(index)
:返回双端队列中指定索引位置的元素的引用。与operator[]
不同,at()
会进行边界检查,并在索引越界时抛出std::out_of_range
异常。 -
begin()
:返回指向双端队列第一个元素的迭代器。 -
end()
:返回指向双端队列最后一个元素后面位置的迭代器(尾后迭代器)。 -
rbegin()
:返回指向双端队列最后一个元素的反向迭代器。 -
rend()
:返回指向双端队列第一个元素前面位置的反向迭代器(逆尾后迭代器)。 -
insert(pos, value)
:在指定位置之前插入一个元素。 -
erase(pos)
:删除指定位置的元素。 -
erase(first, last)
:删除指定范围内的元素。 -
swap(other)
:将双端队列与另一个双端队列进行交换。
这些是deque
容器中的一些常用函数。使用这些函数,可以方便地对双端队列进行插入、删除、访问和操作。注意,deque
还继承了vector
的一部分函数,因此一些vector
的函数也可以在deque
中使用。要使用deque
,请包含<deque>
头文件
#include <iostream> #include <deque> int main() { std::deque<std::string> words; // 使用emplace函数就地构造新元素并插入到deque中 words.emplace(words.begin(), "Hello"); words.emplace_back("World"); // 遍历输出deque中的元素 for (const auto& word : words) { std::cout << word << " "; } std::cout << std::endl; return 0; }
priority_queue
是 C++ STL 提供的一个容器适配器(Container Adapter),用于实现优先队列(Priority Queue)。优先队列是一种特殊的队列,其中的元素按照一定的优先级进行排序,具有较高优先级的元素排在队列的前面。
常见的 priority_queue
函数如下:
-
构造函数
priority_queue()
: 创建一个空的优先队列。priority_queue(const Compare& cmp)
: 使用自定义的比较函数cmp
创建一个空的优先队列。priority_queue(const Container& cont)
: 使用容器cont
中的元素创建一个优先队列。priority_queue(const Container& cont, const Compare& cmp)
: 使用容器cont
中的元素和自定义的比较函数cmp
创建一个优先队列。
-
修改容器
push(const T& value)
: 将value
插入优先队列中,并根据优先级进行排序。pop()
: 删除队列顶部的元素,即具有最高优先级的元素。emplace(Args&&... args)
: 就地构造一个元素,并将其插入到优先队列中。
-
访问元素
top()
: 获取队列顶部的元素,即具有最高优先级的元素。
-
容量和状态
empty()
: 检查队列是否为空,返回布尔值。size()
: 返回队列中元素的个数。
需要注意的是,priority_queue
默认使用 operator<
运算符来比较元素的优先级,即较大的元素优先级更高。如果需要自定义比较函数,可以通过提供自定义的比较函数或使用函数对象来指定排序规则。
以下是一个使用 priority_queue
的示例程序:
#include <iostream>
#include <queue>
int main() {
std::priority_queue<int> pq;
pq.push(30);
pq.push(10);
pq.push(50);
std::cout << "Top element: " << pq.top() << std::endl; // 输出:Top element: 50
pq.pop();
std::cout << "Top element after pop: " << pq.top() << std::endl; // 输出:Top element after pop: 30
std::cout << "Size of priority queue: " << pq.size() << std::endl; // 输出:Size of priority queue: 2
return 0;
}
在上述示例中,我们使用 priority_queue
来保存整数元素,并插入了 30、10 和 50。根据默认的比较规则(operator<
),较大的元素具有较高的优先级。通过 top
函数,我们获得了优先队列的顶部元素。然后,使用 pop
函数移除队列顶部的元素,并展示了队列尺寸(通过 size
函数)。
单调队列(Monotonic Queue)是一种特殊的数据结构,用于解决一类与窗口(滑动窗口)相关的算法问题。它是在队列的基础上进行了扩展和优化,可以在常数时间内获取当前窗口的最大值或最小值。
单调队列可以分为两种类型:单调递增队列和单调递减队列。单调递增队列中,队列中的元素从队首到队尾按照递增的顺序排列,而单调递减队列则相反,元素按照递减的顺序排列。
单调队列主要提供以下两个操作:
- push(x): 将元素 x 插入队尾,并保持队列的单调性。在插入新元素时,会将队列中小于x的元素都从队尾移除,以保持递增或递减的单调性。
- pop(): 移除队首元素。
通过单调队列,我们可以快速获取当前窗口的最大值或最小值。在滑动窗口问题中,我们可以使用单调队列来维护一个窗口内的最大(最小)元素,使得在窗口滑动时能够在常数时间内更新最大(最小)值,而不需要遍历窗口内的所有元素。
常见的滑动窗口问题,如找到最大滑动窗口、找到最小滑动窗口、找到滑动窗口中的最大值与最小值之差等,都可以使用单调队列解决。单调队列在时间复杂度和空间复杂度上都有较好的性能表现,因此在处理滑动窗口问题时是一种很有效的数据结构。
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
堆 一个完全二叉树
小根堆 每个父节点元素要小于他的子节点
大根堆 每个父节点元素要大于他的子节点
存储 先层序遍历编个号 再用数组存储
节点下表为i
左子节点下标为2i+1
右子节点下标为2i+2
下滤:我们吧根节点向下调整的操作为下滤,(根节点破坏了堆序性)
上滤:和他的父节点比较(树的最后一个节点元素破坏了堆序性)用于插入新元素到堆中o(logn)
建堆:自顶向下 将数组中的元素插入堆 然后上滤o(nlogn)
自下而上 从倒数第二排开始对每个父节点进行下滤操作直到根节点操作完毕 o(n)
优先队列 小根堆 弹出最小元素 将最后一个元素放到根节点 然后下滤
堆排序用大根堆是正序
用小根堆是逆序
2.默认优先输出大数据
priority_queue<Type, Container, Functional>
其中, Type 为数据类型. Container 为保存数据的容器. Functional 为元素比较的方式.
若不写后面两个参数.
容器 默认使用 vector
比较方式 默认使用 operator < 即优先队列是大顶堆. 队头元素最大
大根堆声明方式:
大根堆就是把大的元素放在堆顶的堆。优先队列默认实现的就是大根堆,所以大根堆的声明不需要任何花花肠子,直接按C++STL的声明规则声明即可。
3.优先输出小数据 即小顶堆
priority_queue<int, vector<int>, greater<int> > p;
- 使用
greater<int>
. 即改用operator >
小根堆声明方式
大根堆是把大的元素放堆顶,小根堆就是把小的元素放到堆顶。
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(&cmp)> q(cmp); 解释一下这里
优先队列的模板声明如下:priority_queue <T, Container, Compare>
。
在这里,T
是存储在队列中的元素的类型,即 pair<int, int>
,其中 int
是数组的值,另一个 int
是该值出现的次数。
Container
是用于存储队列元素的容器类型,默认情况下是 std::vector
,因此我们可以简写为 priority_queue<pair<int, int>>
。
Compare
是一个比较函数,用于定义队列中元素的比较方式。在这里,比较函数使用了静态成员函数 cmp
,其作用是比较两个 pair<int, int>
元素的第二个值(即出现次数),并按降序排序。
最后,我们使用 decltype(&cmp)
来指定 priority_queue
对象 q
使用的比较方式为静态成员函数 cmp
。
这样,我们就创建了一个最大堆的优先队列 q
,其中元素是 pair<int, int>
类型,按照出现次数降序排序。
在使用 priority_queue
时,需要传递一个比较函数作为参数来确定优先级的顺序。在你的代码中,比较函数 cmp
是作为一个非静态成员函数进行定义的。然而,priority_queue
要求比较函数为静态成员函数或全局函数。
为解决这个问题,你可以将比较函数 cmp
定义为 static bool cmp(pair<int, int>& m, pair<int, int>& n)
,这样就可以满足 priority_queue
的要求。
同时,在初始化 priority_queue
时,需要指定比较函数的类型。在你的代码中,可以使用 decltype(cmp)*
来获取比较函数的指针类型作为模板参数,即 priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp)*> q(cmp)
。
这样做的目的是确保 priority_queue
在插入元素时能够按照你定义的比较函数的规则进行排序。修复后的代码如下:
class Solution {
public:
static bool cmp(pair<int, int>& m, pair<int, int>& n) {
return m.second > n.second;
}
vector<int> topKFrequent(const vector<int>& nums, int k) {
unordered_map<int, int> occurrences;
for (const auto& v : nums) {
occurrences[v]++;
}
// pair 的第一个元素代表数组的值,第二个元素代表了该值出现的次数
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp)*> q(cmp);
for (const auto& [num, count] : occurrences) {
if (q.size() == k) {
if (q.top().second < count) {
q.pop();
q.push(make_pair(num, count));
}
} else {
q.push(make_pair(num, count));
}
}
vector<int> ret;
while (!q.empty()) {
ret.push_back(q.top().first);
q.pop();
}
return ret;
}
};
这样修改后的代码应该可以正常编译和运行。非常抱歉之前的回答可能引起了困惑,感谢你的指出。如果还有任何疑问,请随时提问。