資料結構基礎(14),資料結構基礎14
鏈式隊列是基於單鏈表的一種儲存表示, 其形狀如所示:
(隊列的隊頭指標指向單鏈表的第一個結點, 隊尾指標指向單鏈表的最後一個結點, 注意沒有無用的空[頭/尾]節點)
用單鏈表表示的鏈式隊列特別適合於資料元素變動比較大的情況, 而且不存在隊列滿而產生溢出的情況;
鏈式隊列結點構造:
[這次我們將節點構造成了類LinkQueue的嵌套類]
struct ChainNode{ ChainNode(const Type &_data, ChainNode *_next = NULL) :data(_data), next(_next) {} Type data; ChainNode *next;};
鏈式隊列構造:
template <typename Type>class LinkQueue{ template <typename T> friend ostream &operator<<(ostream &os, LinkQueue<T> &queue);public: LinkQueue(); ~LinkQueue(); bool isEmpty() const; void push(const Type &data); void pop(); //返回隊首元素 const Type &front() const; //返回隊尾元素 const Type &back() const; //清空隊列 void makeEmpty();private: struct ChainNode { ChainNode(const Type &_data, ChainNode *_next = NULL) :data(_data), next(_next) {} Type data; ChainNode *next; };private: ChainNode *m_front; //隊首指標[注意不是指向一個無用的空節點] ChainNode *m_back; //隊尾指標[注意不是指向一個無用的空節點]};
隊列的構造與析構:
template <typename Type>LinkQueue<Type>::LinkQueue(){ m_front = m_back = NULL;}template <typename Type>LinkQueue<Type>::~LinkQueue(){ makeEmpty();}
隊列的四大操作:
//入隊, 這是鏈式隊列的關鍵template <typename Type>void LinkQueue<Type>::push(const Type &data){ if (isEmpty()) { //如果隊列為空白 //則隊首與隊尾指標共同指向一個新構造的對象 m_front = m_back = new ChainNode(data); } else { //首先讓隊尾的下一位置指向一個新構造的對象 m_back->next = new ChainNode(data); //然後隊尾指標後移 m_back = m_back->next; }}
//出隊template <typename Type>void LinkQueue<Type>::pop(){ if (isEmpty()) throw std::range_error("queue is empty"); ChainNode *deleteNode = m_front; // 隊首指標後移 m_front = m_front->next; delete deleteNode;}
//取隊首元素template <typename Type>const Type &LinkQueue<Type>::front() const{ if (isEmpty()) throw std::range_error("queue is empty"); return (m_front->data);}
//取隊尾元素template <typename Type>const Type &LinkQueue<Type>::back() const{ if (isEmpty()) throw std::range_error("queue is empty"); return (m_back->data);}
清空隊列與判空操作:
template <typename Type>void LinkQueue<Type>::makeEmpty(){ while (!isEmpty()) { pop(); }}
template <typename Type>bool LinkQueue<Type>::isEmpty() const{ return (m_front == NULL);}
輸出隊列所有元素(以做測試):
template <typename Type>ostream &operator<<(ostream &os, LinkQueue<Type> &queue){ for (typename LinkQueue<Type>::ChainNode *currentNode = queue.m_front; currentNode != NULL; currentNode = currentNode->next) { os << currentNode->data << ' '; } return os;}
附-測試代碼:
int main(){ LinkQueue<int> queue; for (int i = 0; i < 10; ++i) { queue.push(rand()%100); } cout << queue << endl; cout << queue.front() << endl; queue.pop(); cout << queue.front() << endl; cout << queue.back() << endl; cout << queue << endl; LinkQueue<char> cQueue; cQueue.push('A'); cout << "cQueue.front = " << cQueue.front() << endl; cout << "cQueue.back = " << cQueue.back() << endl; cQueue.pop(); cout << cQueue << endl; try { cout << "cQueue.front = " << cQueue.front() << endl; cout << "cQueue.back = " << cQueue.back() << endl; } catch(const std::exception &e) { cerr << e.what() << endl; } return 0;}