基礎知識
先進先出。STL中與隊列對應的類模板爲queue
,常用操作:front()
返回第一個元素;back()
返回最後一個元素;push()
向隊尾插入元素;pop()
刪除第一個元素;empty()
檢查容器是否爲空;size()
返回容器的元素數。所有操作都在O(1)
時間內完成。
關於隊列的實現方式,詳見: 棧與隊列-順序隊列與鏈隊列類模板的實現(數據結構基礎 第3周)
應用:兩個棧實現隊列
題目:用兩個棧實現一個隊列。請實現它的兩個函數appendTail和deleteHead,分別完成在隊列尾部插入節點和在隊列頭部刪除結點的功能。
分析:相關題目:用兩個隊列實現一個棧。
代碼實現
template<typename T>
class CQueue {
public:
CQueue(void);
~CQueue(void);
void appendTail(const T& node);
T deleteHead();
private:
stack<T> stack1;
stack<T> stack2;
};
template<typename T>
CQueue<T>::CQueue(void) {}
template<typename T>
CQueue<T>::~CQueue(void) {}
template<typename T>
void CQueue<T>::appendTail(const T& node) {
stack1.push(node);
}
template<typename T>
T CQueue<T>::deleteHead() {
if(stack2.empty()) {
while(!stack1.empty()) {
T data=stack1.top();
stack1.pop();
stack2.push(data);
}
}
if(stack2.empty()) throw "The queue is empty.";
T head=stack2.top();
stack2.pop();
return head;
}
測試用例
應用:滑動窗口的最大值
題目:給定一個數組和滑動窗口的大小,請找出所有滑動窗口裏的最大值。例如,如果輸入數組{2,3,4,2,6,2,5,1}
及滑動窗口的大小3,那麼一共存在6個滑動窗口,它們的最大值分別爲{4,4,6,6,6,5}
,如表8.3所示。
分析方法1,笨方法,老老實實滑動;方法2,對方法1找冗餘,一句話核心思想:維護一個隊列,一直保持隊列的頭元素爲滑動至當前位置時滑窗內的最大元素;方法3,我們實現過用
代碼實現
//笨方法,時間複雜度$O(nk)$
int SlidingWindowMaximum_1(const vector<int>& input, int windowSize, vector<int>& result) {
int dataSize = input.size();
if (windowSize < 1) return 1;
if (dataSize < windowSize) return 1;
deque<int> cache(input.begin(), input.begin()+ windowSize-1);
for (int i = windowSize - 1; i<dataSize; i++) {
cache.push_back(input.at(i));
result.push_back(*max_element(cache.begin(), cache.end())); //此句時間複雜度爲O(K)
cache.pop_front();
}
return 0;
}
//找冗餘,時間複雜度$O(n)$
//核心思想:維護一個隊列,一直保持隊列的頭元素爲滑動至位置i時滑窗內的最大元素。
int SlidingWindowMaximum_2(const vector<int>& input, int windowSize, vector<int>& result) {
int dataSize = input.size();
if (windowSize < 1) return 1;
if (dataSize < windowSize) return 1;
deque<int> cache(input.begin(), input.begin() + windowSize - 1);
for (int i = windowSize - 1; i<dataSize; i++) {
if (cache.size() >= windowSize) { //隊列已滿
cache.pop_front(); //取出第一個
cache.push_back(input.at(i));
cache.erase(cache.begin(), max_element(cache.begin(), cache.end()) ); //隊列中最大元素之前的元素已毫無意義
}
else {
if (!cache.empty() && input.at(i) > cache.front()) { //如果元素i大於隊列中的最大元素(即頭元素),則隊列中已存的所有元素已毫無意義。此處一定要判斷隊列是否爲空,要不然怎麼能取頭元素front()呢?
cache.clear();
}
cache.push_back(input.at(i));
}
result.push_back(cache.front()); //此句時間複雜度爲O(K)
}
return 0;
}
測試用例
vector<int> input = { 2, 3, 4, 2, 6, 2, 5, 1 };
應用:從上往下打印二叉樹
題目: 從上往下打印出二叉樹的每個結點,同一層的結點按照從左到右的順序打印。
分析: 也就是樹的層序遍歷了。
代碼實現
int SequenceTraversalByQueue(BinaryTreeNode* root) {
if(!root) return 1;
queue<BinaryTreeNode*> q;
q.push(root);
BinaryTreeNode* p=NULL;
while(!q.emtpy()){
p=q.front();
cout << p->value << " ";
if(p->left) q.push(p->left);
if(p->right) q.push(p->right);
q.pop();
}
return 0;
}