天天看點

一點 · 隊列

隊列

隊列queue也是一種線性表,但它被限制為隻能在隊尾插入,稱為入隊操作(enqueue),從隊首删除,稱為出隊操作(dequeue),是以也被稱為FIFO線性表,即先進先出。

隊列的ADT

template <typename E> class Queue {
private:
  void operator =(const Queue&) {}     // Protect assignment
  Queue(const Queue&) {}         // Protect copy constructor

public:
  Queue() {}          // Default
  virtual ~Queue() {} // Base destructor

  // Reinitialize the queue.  The user is responsible for
  // reclaiming the storage used by the queue elements.
  virtual void clear() = 0;

  // Place an element at the rear of the queue.
  // it: The element being enqueued.
  virtual void enqueue(const E&) = 0;

  // Remove and return element at the front of the queue.
  // Return: The element at the front of the queue.
  virtual E dequeue() = 0;

  // Return: A copy of the front element.
  virtual const E& frontValue() const = 0;

  // Return: The number of elements in the queue.
  virtual int length() const = 0;
};
           

如果使用普通的順序表來實作隊列,就會導緻enqueue和dequeue操作中,一個時間代價為Θ(n),另一個為Θ(1),分别對應隊首隊尾正放與倒放的情況。

是以采用一種循環順序表的方式來實作,即順序表的最後一個結點的next指針指向head,且每次enqueue操作使得front後移,dequeue操作使得rear也後移。

這帶來一個小問題,就是對于一個有着n長度的順序表來說,它應該能表示n+1種狀态,但是由于front和rear各指向一個位置,導緻實際上隻能表示n種狀态,這就是的第一種狀态,空狀态,和第n+1種狀态,滿狀态的區分上産生了困難,一種解決方法是單獨設定一個布爾成員變量,用來記錄是否為空,或者将順序表長度設為n+1,隻在其中儲存最多n個元素,便可表示,n+1種狀态。

鍊式隊列 一種簡單修改後的連結清單,隻是固定front和rear指針指向連結清單的的頭和尾,但是隻能在front處删除,在rear處添加,而初始化時,将front和rear均指向頭結點。 鍊式隊列的實作:

template <typename E> class LQueue: public Queue<E> {
private:
  Link<E>* front;       // Pointer to front queue node
  Link<E>* rear;        // Pointer to rear queue node
  int size;                // Number of elements in queue

public:
  LQueue(int sz =defaultSize) // Constructor 
    { front = rear = new Link<E>(); size = 0; }

  ~LQueue() { clear(); delete front; }      // Destructor

  void clear() {           // Clear queue
    while(front->next != NULL) { // Delete each link node
      rear = front;
      delete rear;
    }
    rear = front;
    size = 0;
  }

  void enqueue(const E& it) { // Put element on rear
    rear->next = new Link<E>(it, NULL);
    rear = rear->next;
    size++;
  }

  E dequeue() {              // Remove element from front
    Assert(size != 0, "Queue is empty");
    E it = front->next->element;  // Store dequeued value
    Link<E>* ltemp = front->next; // Hold dequeued link
    front->next = ltemp->next;       // Advance front
    if (rear == ltemp) rear = front; // Dequeue last element
    delete ltemp;                    // Delete link
    size --;
    return it;                       // Return element value
  }

  const E& frontValue() const { // Get front element
    Assert(size != 0, "Queue is empty");
    return front->next->element;
  }

  virtual int length() const { return size; }
};
           

繼續閱讀