問題:設計一個隊列能夠在O(1)時間內取得隊列的最大值。
分析:
這個問題和設計一個在O(1)時間內取最大值的堆棧看似比較相似,但實現難度要比最大值的堆棧困難一些,開始想模仿最大值堆棧的思想來設計取最大值的堆棧都失敗了。實際上這個問題可以拆分成兩個問題:
1)設計一個在O(1)時間內取最大值的堆棧;
2)如何使用堆棧來實現一個隊列;
如果這兩個問題解決了,O(1)時間取最大值的隊列也就解決了,這體現了把一個困難的問題,分解爲幾個比較簡單的問題,分步驟處理的思想。
首先看第一個問題:設計一個在O(1)時間內取最大值的堆棧是比較容易的,我們可以使用兩個堆棧來保存數據,其中一個保存正常的數據,另一個保存最大值,最大值堆棧在壓棧前需要比較待壓棧的元素與棧頂元素的大小,如果比棧頂大,那麼是一個新的最大值,應該壓入棧,否則保持當前最大值不變,也就是不壓棧。彈出數據時,如果彈出的值和最大值棧的棧頂元素相同,說明最大值被彈出,此時最大值棧也應該跟着出棧,這樣可以保持最大值的更新。
再看第二個問題,可以使用兩個棧來實現一個隊列,隊列push時,將數據壓入A棧中,Pop數據時,如果B棧爲空,將A棧的數據Pop出來,壓入B棧中,再Pop B棧的數據;當隊列Pop時,如果B棧的數據不爲空,則直接Pop B棧的數據。
取隊列的Max就是取A棧和B棧的Max,而A、B棧都是我們剛纔實現的最大值棧,他們取最大值的時間都是O(1),因此隊列取最大值複雜度也是O(1)。但實現是要注意A、B棧有可能爲空,在我們的實現中,對於空棧取最大值是未定義的,因此在對A、B棧取最大值時要先判斷是否爲空棧。
最後從複雜度來說,隊列的Pop操作最壞情況是將A棧的數據都壓入B棧,在Pop B棧的數據,最差是O(n),實際多數情況都是O(1)。
總結一下:這個問題,非常明顯的體現瞭如何將一個新問題轉成兩個已知的簡單問題,同時MaxStack的實現封裝了複雜性,使得後面的實現更加簡單。
代碼如下:
#include <stdio.h>
#include <queue>
#include <stack>
template<typename T>
class MaxStack {
public:
void Push(const T& value) {
data_.push(value);
if (max_element_.empty()) {
max_element_.push(value);
} else if (value >= max_element_.top()) {
max_element_.push(value);
}
}
T Top() {
return data_.top();
}
void Pop() {
if (data_.top() == max_element_.top()) {
max_element_.pop();
}
data_.pop();
}
bool Empty() {
return data_.empty();
}
T Max() {
if (!max_element_.empty()) {
return max_element_.top();
}
}
private:
std::stack<T> data_;
std::stack<T> max_element_;
};
template<typename T>
class MaxQueue {
public:
void Push(const T& value) {
push_stack_.Push(value);
}
T Front() {
if (pop_stack_.empty()) {
while (!push_stack_.Empty()) {
pop_stack_.Push(push_stack_.Top());
push_stack_.Pop();
}
}
return pop_stack_.Top();
}
void Pop() {
if (pop_stack_.Empty()) {
while (!push_stack_.Empty()) {
pop_stack_.Push(push_stack_.Top());
push_stack_.Pop();
}
}
pop_stack_.Pop();
}
bool IsEmpty() {
return push_stack_.Empty() && pop_stack_.Empty();
}
T Max() {
if (!push_stack_.Empty() && !pop_stack_.Empty()) {
return push_stack_.Max() > pop_stack_.Max() ? push_stack_.Max() : pop_stack_.Max();
} else if (push_stack_.Empty() && !pop_stack_.Empty()) {
return pop_stack_.Max();
} else if (!push_stack_.Empty() && pop_stack_.Empty()) {
return push_stack_.Max();
} else {
// throw RUNTIME_ERROR;
}
}
private:
MaxStack<T> push_stack_;
MaxStack<T> pop_stack_;
};
int main(int argc, char** argv) {
MaxQueue<int> max_queue;
max_queue.Push(1);
max_queue.Push(2);
max_queue.Push(6);
max_queue.Push(4);
max_queue.Push(5);
max_queue.Push(2);
printf("max %d\n", max_queue.Max());
max_queue.Pop();
printf("max %d\n", max_queue.Max());
max_queue.Pop();
printf("max %d\n", max_queue.Max());
max_queue.Pop();
printf("max %d\n", max_queue.Max());
max_queue.Pop();
printf("max %d\n", max_queue.Max());
max_queue.Pop();
printf("max %d\n", max_queue.Max());
}
參考文獻:
編程之美3.7