iT邦幫忙

2021 iThome 鐵人賽

DAY 11
0
Software Development

程式菜鳥自學C++資料結構演算法系列 第 11

[Day11]程式菜鳥自學C++資料結構演算法 – 佇 列Queue

  • 分享至 

  • xImage
  •  

前言:上一篇結束了堆疊的實作,今天要來介紹新東西「佇列」。

佇列的特性:佇列和堆疊非常類似,同樣都是有序串列(元素以某種順序排列 ,該順序具有一定的意義,不可錯置),且同樣屬於抽象資料型態。
佇列與堆疊的差別在於佇列為「先進先出(FIFO,First In First Out)」,就好比先排隊的人先買到門票一樣。
https://ithelp.ithome.com.tw/upload/images/20210925/201401870cb7Mn9HiT.png
圖片來源:http://runningmanmacau.weebly.com/uploads/2/7/2/0/27203993/s416834513424666157_p2_i1_w640.jpeg

如果以電腦的角度來看,堆疊的新增和刪除只能發生在頭節點,而佇列多了一個後端指標負責新增資料,前端指標用來讀取和刪除。
https://ithelp.ithome.com.tw/upload/images/20210925/20140187xrkSsfy3Gy.png

環狀佇列:佇列的實際應用之一,經常用於行車紀錄器或監視器之類的裝置,儲存特定天數的資料,若天數已滿則將第一天從前端刪除,並從末端加入新的一天。
https://ithelp.ithome.com.tw/upload/images/20210925/20140187ZCMK2RvON6.png
https://ithelp.ithome.com.tw/upload/images/20210925/201401871mvCguRtry.png
https://ithelp.ithome.com.tw/upload/images/20210925/20140187lnsp6dgbgm.png
依照這樣的做法就能成功創建了喔!

接著就實際操作看看,一樣要先創建新的專案୧| ” •̀ ل͜ •́ ” |୨

佇列:

https://ithelp.ithome.com.tw/upload/images/20210925/20140187MGq8GaWeeT.png
https://ithelp.ithome.com.tw/upload/images/20210925/20140187lHd0Og0dNp.png

std::cout << Q.front() << std::endl;為顯示佇列前端指標的資料,所以可以看到12位在佇列最前端,將其pop之後最前端的位置就變為3。
https://ithelp.ithome.com.tw/upload/images/20210925/20140187sgM3iySKwR.png

也可持續pop直到佇列為空的,首先要判斷佇列是否沒有資料。
https://ithelp.ithome.com.tw/upload/images/20210925/20140187ixtWPBZoIR.png
https://ithelp.ithome.com.tw/upload/images/20210925/20140187ntCN1FLYZL.png

這樣就完成最初始的佇列了喔,緊接著就來挑戰進階一些的環狀佇列。

環狀佇列:

直接在資源檔中新增項目即可,不需要創建新的專案。但同樣一個專案不能有兩個main程式,如果不知道怎麼操作的,可以看看上一篇文章

之後就可以開始實作了。
https://ithelp.ithome.com.tw/upload/images/20210925/20140187PRroxUhdRC.png
https://ithelp.ithome.com.tw/upload/images/20210925/201401872eWAIf3diE.png

因為是環狀佇列,所以也可以從末端查詢資料。
https://ithelp.ithome.com.tw/upload/images/20210925/20140187BK6CYeyFcO.png
這樣就完成了喔!

本日小結:今天做完了佇列和循環佇列,循環佇列和佇列的概念非常類似,但是如果要對循環佇列進行新增和刪除的話,都必須要用除以容量的餘數去考慮,這個部分比較複雜,需要花時間理解,佇列還有一些東西沒講到,會在之後的文章說明,明天將要進入資料結構中最重要的一環「樹」的部分१|˚–˚|५

佇列

#include<iostream>
using namespace std;

template<class T> class Queue {
	struct Node { //設立節點前端和後端指標
		T data;
		Node* next;
	};
	Node* front_;
	Node* rear;

public: //宣告函式
	Queue();
	bool push(T e);
	bool pop();
	T& front() { //查詢位在前端指標的資料
		if (front_ == rear) throw"佇列為空";
		return front_->next->data;
	}
	bool empty() {
		return front_ == rear;
	}
};

template<class T>
Queue<T>::Queue() { //初始化佇列
	front_ = rear = new Node();
	if (!front_) throw "No Memory";
	front_->next = 0;
}

template<class T> 
bool Queue<T>::push(T e) { //將資料新增置後端指標
	Node* p = new Node;
	if (!p)return false;
	p->data = e; p->next = 0;
	rear->next = p;
	rear = p;
	return true;
}
template<class T>
bool Queue<T>::pop() { // 將資料從前端指標刪除
	if (front_ == rear) return false;
	Node* p = front_->next;
	front_->next = p->next;
	if (rear == p) rear = front_;
	delete p;
	return true;
}

int main() {
	Queue<int> Q;
	Q.push(12); 
	Q.push(3); 
	Q.push(6); 
	std::cout << Q.front() << std::endl;
	Q.pop();
	std::cout << Q.front() << std::endl << std::endl;

	Q.push(30);
	Q.push(16);
	while (!Q.empty()) {
		std::cout << Q.front() << std::endl;
		Q.pop();
	}
}

環狀佇列

#include<iostream>
using namespace std;

template<typename T>
class SqlQueue { //創建新的佇列,並宣告會用到的變數名稱
	T* data;
	int front_, rear_, capacity;
public:
	SqlQueue(int cap = 3) {
		data = new T[cap]; if(!data) throw "儲存空間份配失敗";
		capacity = cap;
		front_ = rear_ = 0; //表示空陣列
	}
	bool push(T e) {
		if ((rear_ + 1) % capacity == front_) {
			T* p = new T[2 * capacity];
			if(!p) return false; //檢查佇列是否已滿,若rear_+1的餘數等於front,則佇列已滿
			for (int i = 0; i < capacity; i++)
				p[i] = data[i];
			delete[] data;
			data = p;
			capacity *= 2;
		}
		data[rear_] = e; rear_ = (rear_ + 1) % capacity; //%為相除的餘數 ex:3%5=2
		return true;
	}
	bool pop() {
		if (front_ == rear_) return false;
		front_ = (front_ + 1) % capacity;
		return true;
	}
	T& front() {
		if (front_ == rear_) throw "佇列為空";
		return data[front_];
	}
	T& rear() {
		if (front_ == rear_) throw "佇列為空";
		return data[(rear_ - 1 + capacity) % capacity];
	}
	int size() {
		return (rear_ - front_ + capacity) % capacity;
	} 
	bool empty() {
		return front_ == rear_;
	}
	bool clear() {
		front_ = rear_ = 0;
	}
};

int main() {
	SqlQueue<int> Q;
	Q.push(54);
	Q.push(94);
	Q.push(67);
	Q.push(39);
	Q.push(86);
	Q.push(13);
	int r = Q.rear();
	std::cout << r << std::endl;
	while (!Q.empty()) {
		int f = Q.front();
		Q.pop();
		std::cout << f << " ";
	}
	std::cout << std::endl;
}

上一篇
[Day10]程式菜鳥自學C++資料結構演算法 – 堆 疊應用:數制轉換&括號匹配&漢諾塔
下一篇
[Day12]程式菜鳥自學C++資料結構演算法 – 樹Tree
系列文
程式菜鳥自學C++資料結構演算法30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言