隊列中取最大值操作問題

問題:設計一個隊列能夠在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

發佈了82 篇原創文章 · 獲贊 3 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章