四、佇列的概念和實現
佇列是一種特殊的線性表。
佇列僅能線上性表的兩端進行操作:
隊頭(Front):取出資料元素的一端;
隊尾(Rear):插入資料元素的一端。
佇列的特性——先進先出(First In First Out)
佇列的操作:建立、銷燬、清空(clear())、進佇列(add())、出佇列(remove())、獲取隊頭元素(front())、獲取隊尾元素(length())。
父類佇列的實現:
template <typename T>
class Queue : public Object
{
public:
virtual void add(const T& e) = 0;
virtual void remove() = 0;
virtual T front() const = 0;
virtual void clear() = 0;
virtual int length() const = 0;
};
一、佇列的順序實現(StaticQueue)
類别範本:使用原生陣列作為佇列的儲存空間。
使用模板引數(N)決定佇列的最大容量。
StaticQueue實現要點(迴圈計數法):
關鍵操作:
具體實現如下:
template <typename T, int N> //使用模板引數決定佇列的最大容量
class StaticQueue : public Queue<T>
{
protected:
T m_space[N]; //佇列儲存空間,N為模板引數
int m_front; //隊頂標識
int m_rear; //隊尾標識
int m_length; //當前佇列的大小
public:
StaticQueue()
{
m_rear = 0;
m_length = 0;
m_front = 0;
}
int capacity() const
{
return N;
}
/***********迴圈計數法***********/
void add(const T& e) //O(1)
{
if( m_length < N)
{
m_space[m_rear] = e;
m_rear = (m_rear + 1) % N; //迴圈計數
m_length++;
}
else
{
THROW_EXCEPTION(InvalidOperationException,"No space in current queue...");
}
}
void remove()//O(1)
{
if( 0 < m_length)
{
m_front = (m_front + 1) % N; //變換隊頭
m_length--;
}
else
{
THROW_EXCEPTION(InvalidOperationException,"No element in current queue...");
}
}
T front() const//O(1)
{
if( m_length > 0)
{
return m_space[m_front];
}
else
{
THROW_EXCEPTION(InvalidOperationException,"No element in current queue...");
}
}
void clear()//O(1)
{
m_front = 0;
m_rear = 0;
m_length = 0;
}
int length() const//O(1)
{
cout<< m_front - m_rear<<endl;
cout<< "printf again!" << endl;
cout<< m_length <<endl;
return m_length;
}
};
執行測試程式碼
int main()
{
StaticQueue<int, 5> sq;
for(int i=0; i<5; i++)
{
sq.add(i);
}
while (sq.length() > 0)
{
cout << sq.front() << endl;
sq.remove();
}
return 0;
}
輸出:01234。
小結:佇列是一種特殊的線性表,具有先進先出的特性;
佇列只允許線上性表的兩端進行操作,一端進,一端出;
StaticQueue使用原生陣列作為內部儲存空間;
StaticQueue的最大容量由模板引數決定;
StaticQueue採用迴圈計數法來提高佇列操作效率。
二、鏈式佇列(LinkQueue)的實現
當資料元素為類型別,StaticQueen的物件在建立時,會多次呼叫元素型別的建構函式,影響效率。
設計要點:類别範本,抽象父類Queue的直接子類;
在內部使用鏈式結構實現元素的儲存;
只在連結串列的頭部和尾部進行操作。
在鏈式棧的實現中,可以使用單連結串列來實現,但是因為涉及到遍歷操作(insert()),所以效率上並不是很高。
佇列鏈式儲存實現的優化:
通過Linux核心連結串列來實現鏈式佇列:
template <typename T>
class LinkQueue : public Queue<T>
{
protected:
//LinkList<T> m_list;
struct Node : public Object //帶頭結點 使用Linux核心連結串列
{
list_head head;
T value;
};
list_head m_header;
int m_length;
public:
LinkQueue()
{
m_length = 0;
INIT_LIST_HEAD(&m_header); //初始化
}
void add(const T& e)
{
//m_list.insert(e); //O(n) 與佇列的元素個數成正比
Node* node = new Node();
if( node != NULL)
{
node->value = e;
list_add_tail(&node->head, &m_header); //O(1)
m_length++;
}
else
{
THROW_EXCEPTION(InvalidOperationException,"No memory to add new element...");
}
}
void remove() //O(1)
{
if(m_length > 0)
{
//m_list.remove(0);
list_head* toDel = m_header.next; //頭結點指向的位置
list_del(toDel); //Linux核心連結串列的函式
m_length--;
delete list_entry(toDel, Node, head);
}
else
{
THROW_EXCEPTION(InvalidOperationException,"No element in current queue...");
}
}
T front() const //O(1)
{
if( m_length > 0)
{
return list_entry(m_header.next, Node, head)->value;
}
else
{
THROW_EXCEPTION(InvalidOperationException,"No element in current queue...");
}
}
void clear() //O(n)
{
while( m_length > 0)
{
remove();
}
}
int length() const//O(1)
{
return m_length;
}
~LinkQueue()
{
clear();
}
};
測試程式碼如下,在主函式中實現一個Test類,使用鏈式佇列來儲存這個類作為佇列成員。
class Test : public Object
{
public:
Test()
{
cout << "Test()" <<endl;
}
~Test()
{
cout << "~Test()" <<endl;
}
};
int main()
{
LinkQueue<int> lq;
LinkQueue<Test> lq1;
StaticQueue<Test, 10> lq2;
for(int i=0; i<5; i++)
{
lq.add(i);
}
while (lq.length() > 0)
{
cout << lq.front() << endl;
lq.remove();
}
return 0;
}
通過列印結果可以看出,順序佇列在實現自定義類型別資料元素儲存時,需要將每個物件的建構函式和解構函式都呼叫(原因參見《二、單連結串列的實現和遍歷,迴圈連結串列、雙向迴圈連結串列的實現》中的第二節——單連結串列的具體實現),效率不高。鏈式佇列則沒有這種效率上的缺點,直接將資料儲存在佇列中。小結:StaticQueue在初始化的時候可能多次呼叫元素型別的建構函式;
LinkList的組合使用,可以實現鏈式佇列的功能,但是效率不高;
LinkQueue的最終實現使用了Linux核心連結串列;
LinkQueue中入隊和出隊的操作可以在常量時間內完成。
相關文章
- 實驗四 棧和佇列的基本操作佇列
- 稀疏陣列、佇列的概念與實踐陣列佇列
- GCD之佇列的實現和使用GC佇列
- 佇列的一種實現:迴圈佇列佇列
- Python佇列的三種佇列實現方法Python佇列
- 實現簡單延遲佇列和分散式延遲佇列佇列分散式
- 通過佇列實現棧OR通過棧實現佇列佇列
- 【freertos】010-訊息佇列概念及其實現細節佇列
- 【資料結構】佇列(順序佇列、鏈佇列)的JAVA程式碼實現資料結構佇列Java
- 9. 題目:對佇列實現棧&用棧實現佇列佇列
- 鏈式佇列的實現方式佇列
- Golang 實現 RabbitMQ 的死信佇列GolangMQ佇列
- 用棧實現佇列佇列
- 用佇列實現棧佇列
- 用 Rust 實現佇列Rust佇列
- 佇列(Queue)-c實現佇列
- 資料結構-js實現棧和佇列資料結構JS佇列
- Laravel 在事件監聽中實現佇列的方法以及指定加入的佇列名稱和佇列延遲時間Laravel事件佇列
- 鏈式佇列—用連結串列來實現佇列佇列
- 佇列 優先順序佇列 python 程式碼實現佇列Python
- 訊息佇列概念與作用佇列
- Day 10| 232.用棧實現佇列 、 225. 用佇列實現棧佇列
- 佇列 和 迴圈佇列佇列
- Golang 實現 RabbitMQ 的延遲佇列GolangMQ佇列
- RabbitMQ實現延遲佇列MQ佇列
- RabbitMQ 實現延遲佇列MQ佇列
- Redis實現訊息佇列Redis佇列
- 兩個棧實現佇列佇列
- 用訊息佇列和socket實現聊天系統佇列
- 靜態佇列,迴圈陣列實現佇列陣列
- 訊息佇列概念與認知佇列
- 阻塞佇列——四組API佇列API
- 詳細分析棧和佇列的資料結構的實現過程(Java 實現)佇列資料結構Java
- 迴圈佇列的實現及細節佇列
- Python 通過List 實現佇列的操作Python佇列
- 用連結串列實現佇列的功能佇列
- RabbitMQ使用 prefetch_count優化佇列的消費,使用死信佇列和延遲佇列實現訊息的定時重試,golang版本MQ優化佇列Golang
- leedcode-用佇列實現棧佇列