關於 C++ 隊列算法,你該瞭解這些【第三集:線性池中的任務隊列】

上集回顧:鏈式存儲隊列

第一集:順序存儲隊列
第二集:鏈式存儲隊列


觀看本系列博文提醒:
你將學會隊列的兩種最基本的表現形式:順序存儲隊列鏈式存儲隊列
一個擴展隊列的使用方法:循環隊列
兩個企業級隊列的應用:線性池中的任務隊列優先鏈式存儲隊列


隊列的原理

隊列是一種受限的線性表,(Queue),它是一種運算受限的線性表,先進先出(FIFO First In First Out).
在這裏插入圖片描述
例如上圖中,圓球1先進,也是圓球1先出。

隊列是一種受限的線性結構

  1. 它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作。
  2. 生活中隊列場景隨處可見: 比如在電影院, 商場, 或者廁所排隊。。。。。。

在這裏插入圖片描述
由上圖我們可以知道,隊列中有兩個“指針”,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;
}

運行截圖:
在這裏插入圖片描述


注意:由於一篇博客內容太多,所以我將會把他分成幾篇進行講解!

祝各位學習愉快!


下集預告:
你將學會一個擴展隊列的使用方法:循環隊列
請持續關注!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章