上集回顧:鏈式存儲隊列
觀看本系列博文提醒:
你將學會隊列的兩種最基本的表現形式:順序存儲隊列 和 鏈式存儲隊列;
一個擴展隊列的使用方法:循環隊列;
兩個企業級隊列的應用:線性池中的任務隊列 和 優先鏈式存儲隊列。
隊列的原理
隊列是一種受限的線性表,(Queue),它是一種運算受限的線性表,先進先出(FIFO First In First Out).
例如上圖中,圓球1先進,也是圓球1先出。
隊列是一種受限的線性結構
- 它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作。
- 生活中隊列場景隨處可見: 比如在電影院, 商場, 或者廁所排隊。。。。。。
由上圖我們可以知道,隊列中有兩個“指針”,front指向隊首,rear指向隊尾;
至於length,他是整個隊列的總長度(因爲一個隊列他是有固定長度的)。
線性池中的任務隊列
線程池 - 由一個任務隊列和一組處理隊列的線程組成。一旦工作進程需要處理某個可能“阻塞”的操作,不用自己操作,將其作爲一個任務放到線程池的隊列,接着會被某個空閒線程提取處理。
簡單來說,就是節點出隊時,函數指針調用的函數處理一系列的任務!
這算是上一集鏈式存儲隊列的練習題吧!
他的代碼和鏈式存儲隊列的代碼幾乎完全一樣,只是的節點多定義了一個函數指針,用於存儲函數的地址。代碼上也多了一些。
但是總體設計,總體思路都還是一樣的。
代碼如下:
#include <iostream>
#include <Windows.h>
using namespace std;
#define MaxSize 5 // 隊列的最大容量
//typedef int DateType; // 隊列中元素的類型
typedef struct _QNode { // 節點結構
int id; // 編號id
void (*handler)(); // 函數指針
struct _QNode* next;
}QNode;
typedef QNode* QueuePar;
typedef struct Queue {
int lenght; // 隊列的長度
QueuePar front; // 隊頭指針
QueuePar rear; // 隊尾指針
}LinkQueue;
// 隊列的初始化
bool inItLinkQueue(LinkQueue*& LQ) {
if (!LQ) {
cout << "隊列不存在!" << endl;
return false;
}
LQ->lenght = 0; // 隊列長度值爲零
LQ->front = LQ->rear = NULL; // 把隊首和隊尾指針指向NULL
return true;
}
// 判斷隊列是否爲空
bool estimateLinkQueueEmpty(LinkQueue*& LQ) {
if (!LQ) {
cout << "隊列不存在!" << endl;
return false;
}
if (!LQ->front) {
return true;
}
return false;
}
// 判斷隊列是否已滿
bool estimateLinkQueuefull(LinkQueue*& LQ) {
if (!LQ) {
cout << "隊列不存在!" << endl;
return false;
}
if (LQ->lenght == MaxSize) {
return true;
}
return false;
}
// 入隊,將元素插入隊列中
bool linkQueueInsertValue(LinkQueue*& LQ, QNode*& NQ) {
if (!LQ || !NQ) {
cout << "隊列不存在!" << endl;
return false;
}
if (estimateLinkQueuefull(LQ)) {
cout << "隊列已滿!" << endl;
return false;
}
NQ->next = NULL;
if (!LQ->front) {
LQ->front = LQ->rear = NQ;
} else {
LQ->rear->next = NQ;
LQ->rear = NQ;
}
LQ->lenght += 1;
return true;
}
// 出隊,刪除隊首
QNode* deleteLinkQueueFront(LinkQueue*& LQ) {
if (!LQ) {
cout << "隊列不存在!" << endl;
return 0;
}
if (estimateLinkQueueEmpty(LQ)) {
cout << "鏈表爲空!刪除失敗!" << endl;
return 0;
}
QNode* tem = NULL;
tem = LQ->front;
LQ->front = LQ->front->next;
if (!LQ->front) {
LQ->rear = NULL;
}
LQ->lenght -= 1;
return tem;
}
// 輸出隊列中的元素
bool linkQueuePrint(LinkQueue*& LQ) {
if (!LQ) {
cout << "隊列不存在!" << endl;
return false;
}
if (estimateLinkQueueEmpty(LQ)) {
cout << "鏈表爲空!輸出失敗!" << endl;
return false;
}
QNode* tem = LQ->front; // 定義臨時節點指向隊首指針
cout << "id爲: ";
while (tem) {
cout << tem->id << "\t";
tem = tem->next;
}
cout << endl;
return true;
}
//分配線程執行的任務節點
QNode* thread_task_alloc() {
QNode* tem = new QNode; // 分配內存
if (!tem) { // 判斷是否分配失敗
return 0;
}
return tem; // 返回節點指針
}
void text1(void) {
cout << "第一個函數!" << endl;
}
void text2(void) {
cout << "第二個函數!" << endl;
}
int main(void) {
LinkQueue* LQ = new LinkQueue;
QNode* tem = NULL;
inItLinkQueue(LQ);
// 任務一入隊
tem = thread_task_alloc();
tem->id = 1;
tem->handler = &text1;
linkQueueInsertValue(LQ, tem);
// 任務二入隊
tem = thread_task_alloc();
tem->id = 2;
tem->handler = &text2;
linkQueueInsertValue(LQ, tem);
cout << "隊列的元素有:" << LQ->lenght << "個" << endl;
linkQueuePrint(LQ);
while (tem = deleteLinkQueueFront(LQ)) {
tem->handler();
delete tem;
}
delete LQ;
system("pause");
return 0;
}
運行截圖:
注意:由於一篇博客內容太多,所以我將會把他分成幾篇進行講解!
祝各位學習愉快!
下集預告:
你將學會一個擴展隊列的使用方法:循環隊列;
請持續關注!