最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言超詳細講解隊列的實現(xiàn)及代碼

 更新時間:2022年04月11日 10:41:37   作者:三分苦  
隊列(Queue)與棧一樣,是一種線性存儲結(jié)構(gòu),它具有如下特點:隊列中的數(shù)據(jù)元素遵循“先進先出”(First?In?First?Out)的原則,簡稱FIFO結(jié)構(gòu)。在隊尾添加元素,在隊頭刪除元素

前言

隊列的概念

  • 隊列:只允許在一端進行插入數(shù)據(jù)操作,在另一端進行刪除數(shù)據(jù)操作的特殊線性表,隊列具有先進先出FIFO(First In First Out)
  • 入隊列:進行插入操作的一端稱為隊尾
  • 出隊列:進行刪除操作的一端稱為隊頭

隊列和前文所學的棧還是有一定區(qū)別的,隊列明確指出先進先出。假如說一個隊列的入隊順序為A B C D,那么出隊順序一定為A B C D,因為無論你是在A進去再出來,然后B進去再出來接著CD進去再出來或者類似的,都不會影響它最終的出隊順序A B C D。這點和棧還是有區(qū)別的,畢竟棧是后進先出。

隊列的結(jié)構(gòu)

隊列的應用場景

隊列:

  • 公平排隊
  • 廣度優(yōu)先遍歷 ……

棧:

  • 解決括號匹配
  • 逆波蘭表達式求解
  • 遞歸改非遞歸 ……

隊列的實現(xiàn)

  • 在實現(xiàn)之前,首先得考慮用哪種結(jié)構(gòu)好,是用數(shù)組結(jié)構(gòu)還是鏈式結(jié)構(gòu)呢?上文的棧我們使用的是數(shù)組結(jié)構(gòu),難道隊列也要用嗎?
  • 其實不然。應該使用鏈式結(jié)構(gòu)。前文棧刪除數(shù)據(jù)不需要挪動數(shù)據(jù),使用數(shù)組結(jié)構(gòu)即可滿足需求,而隊列在刪除數(shù)據(jù)時需要把后面的數(shù)據(jù)挪到前面,使用鏈式結(jié)構(gòu)非常容易實現(xiàn),只需改變節(jié)點指向即可,而數(shù)組結(jié)構(gòu)想要實現(xiàn)挪動數(shù)據(jù)則非常麻煩。綜上,使用鏈式結(jié)構(gòu)是最優(yōu)的。此外,單鏈表即可滿足需求,不需要使用其余較為復雜的鏈式結(jié)構(gòu)。

創(chuàng)建隊列結(jié)構(gòu)

思路:

這里要定義兩個結(jié)構(gòu)體,除了要定義1個鏈式結(jié)構(gòu)來記錄各個節(jié)點外,還要定義一個結(jié)構(gòu)來記錄隊頭和隊尾。以此方便后續(xù)的隊尾入數(shù)據(jù),隊頭出數(shù)據(jù)。

Queue.h 文件:

//創(chuàng)建隊列結(jié)構(gòu)
typedef int QDataType; //方便后續(xù)更改存儲數(shù)據(jù)類型,本文以int為例
 //創(chuàng)建隊列節(jié)點
typedef struct QueueNode
{
	QDataType data; //存儲數(shù)據(jù)
	struct QueueNode* next; //記錄下一個節(jié)點
}QNode;
 //保存隊頭和隊尾
typedef struct Queue
{
	QNode* head; //頭指針
	QNode* tail; //尾指針
}Queue;

隊列初始化  

思路:

隊列可以為空,但是管理頭指針和尾指針的結(jié)構(gòu)體不能為空,所以一開始就要斷言。其次,在插入數(shù)據(jù)前,隊列肯定是空的,所以直接把頭指針和尾指針置空即可。

Queue.h 文件:

//初始化隊列
void QueueInit(Queue* pq);

Queue.c 文件:

//初始化隊列
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
}

隊列銷毀  

思路:

銷毀隊列就是把隊列的每個數(shù)據(jù)都銷毀掉,那么需要遍歷鏈表進行挨個銷毀free。首先定義一個cur指針為pq->head,用來保存第一個數(shù)據(jù),遍歷cur,如果不為空,就free。最后把tail和head置空即可。

Queue.h 文件:

//銷毀隊列
void QueueDestory(Queue* pq);

Queue.c 文件:

//銷毀隊列
void QueueDestory(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
}

入隊列  

思路:

入隊列其實很簡單,只需要尾插即可,首先要新創(chuàng)建一個節(jié)點來保存新插入的數(shù)據(jù)。但是在尾插之前要考慮如果一開始隊列沒有數(shù)據(jù),為空,那么只需要把head和tail節(jié)點指向新節(jié)點newnode節(jié)點即可。相反的,如果一開始就有數(shù)據(jù),那么只需正常尾插把tail的next指向新節(jié)點newnode,再把newnode賦給tail即可。

Queue.h 文件:

//入隊列
void QueuePush(Queue* pq, QDataType x);

 Queue.c 文件:

//入隊列
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	//創(chuàng)建一個新節(jié)點保存數(shù)據(jù)
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	//暴力檢測newnode,因為malloc的都要檢測
	assert(newnode);
	newnode->next = NULL;
	newnode->data = x;
	//如果一開始沒有數(shù)據(jù),為空的情況
	if (pq->tail == NULL)
	{
		assert(pq->head == NULL);
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}

出隊列  

思路:

特殊情況:

這里在刪除數(shù)據(jù)時,首先要考慮特殊情況,當刪到只剩一個數(shù)據(jù)時,再刪一次,此時數(shù)據(jù)是沒了,不過head為空了,而tail變成野指針了,為了避免此現(xiàn)象的產(chǎn)生,單獨討論并置空head和tail即可。

一般情況:

此時只需要定義一個next指針保存head的下一個節(jié)點,將head移動到next即可,并把舊的head置空。

 Queue.h 文件:

//出隊列
void QueuePop(Queue* pq);

Queue.c 文件:

//出隊列
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->head && pq->tail); //tail和head均不能為空
	//特殊:當刪到head=tail的位置時
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	//一般情況
	else
	{
		//保存head的下一個節(jié)點
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}

隊列判空  

思路:

如果head為空或者tail為空都是判空的條件,直接返回即可。

Queue.h 文件:

//判空
bool QueueEmpty(Queue* pq);

Queue.c 文件:

//判空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->head == NULL;
}

獲取隊列元素個數(shù)  

思路:

求元素個數(shù)其實不難,只需要定義一個cur指針為第一個數(shù)據(jù)pq->head,定義變量size來記錄個數(shù)。依次遍歷cur,不為空,size就++。這種遍歷的思想不復雜,但時間復雜度達到O(N),不是太好,想要O(1)的話可以直接在當初定義結(jié)構(gòu)體時多定義一個size變量,專門用來記錄有效元素個數(shù),每次入隊列size++,出隊列size--。這樣實現(xiàn)是比較好的,不過為了封裝成一個獨立模塊,還是采用遍歷的方式。如下:

Queue.h 文件:

//獲取有效元素個數(shù)
size_t QueueSize(Queue* pq);

Queue.c 文件:

//獲取有效元素個數(shù)
size_t QueueSize(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	size_t size = 0;
	while (cur)
	{
		size++;
		cur = cur->next;
	}
	return size;
}

獲取隊列頭部元素  

思路:

首先要斷言頭部不能為空,如果頭部都為空了,那還怎么能獲得頭部元素,其次直接返回頭部head的數(shù)據(jù)即可。

Queue.h 文件:

//獲取隊頭元素
QDataType QueueFront(Queue* pq);

Queue.c 文件:

//獲取隊頭元素
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->head); //頭部不能為空
	return pq->head->data;
}

獲取隊列尾部元素  

思路:

有了獲取隊頭元素的經(jīng)驗,隊尾就更簡單了,把head換位tail即可,結(jié)構(gòu)與上文一樣。

Queue.h 文件:

//獲取隊尾元素
QDataType QueueBack(Queue* pq);

Queue.c 文件:

//獲取隊尾元素
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->tail); //尾部不能為空
	return pq->tail->data;
}

總代碼

Queue.h 文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
 
//創(chuàng)建隊列結(jié)構(gòu)
typedef int QDataType; //方便后續(xù)更改存儲數(shù)據(jù)類型,本文以int為例
 //創(chuàng)建隊列節(jié)點
typedef struct QueueNode
{
	QDataType data; //存儲數(shù)據(jù)
	struct QueueNode* next; //記錄下一個節(jié)點
}QNode;
 //保存隊頭和隊尾
typedef struct Queue
{
	QNode* head; //頭指針
	QNode* tail; //尾指針
}Queue;
 
//初始化隊列
void QueueInit(Queue* pq);
 
//銷毀隊列
void QueueDestory(Queue* pq);
 
//入隊列
void QueuePush(Queue* pq, QDataType x);
 
//出隊列
void QueuePop(Queue* pq);
 
//判空
bool QueueEmpty(Queue* pq);
 
//獲取有效元素個數(shù)
size_t QueueSize(Queue* pq);
 
//獲取隊頭元素
QDataType QueueFront(Queue* pq);
 
//獲取隊尾元素
QDataType QueueBack(Queue* pq);

Queue.c 文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"
 
//初始化隊列
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
}
 
//銷毀隊列
void QueueDestory(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
}
 
//入隊列
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	//創(chuàng)建一個新節(jié)點保存數(shù)據(jù)
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	//暴力檢測newnode,因為malloc的都要檢測
	assert(newnode);
	newnode->next = NULL;
	newnode->data = x;
	//如果一開始沒有數(shù)據(jù),為空的情況
	if (pq->tail == NULL)
	{
		assert(pq->head == NULL);
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}
 
//出隊列
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->head && pq->tail); //tail和head均不能為空
	//特殊:當刪到head=tail的位置時
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	//一般情況
	else
	{
		//保存head的下一個節(jié)點
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}
 
//判空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->head == NULL;
}
 
//獲取有效元素個數(shù)
size_t QueueSize(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	size_t size = 0;
	while (cur)
	{
		size++;
		cur = cur->next;
	}
	return size;
}
 
//獲取隊頭元素
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->head); //頭部不能為空
	return pq->head->data;
}
 
//獲取隊尾元素
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->tail); //尾部不能為空
	return pq->tail->data;
}

Test.c 文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"
void TestQueue()
{
	Queue q;
	QueueInit(&q);
	//插入數(shù)據(jù)
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	//打印
	while (!QueueEmpty(&q))
	{
		printf("%d ", QueueFront(&q));
		QueuePop(&q);
	}
	printf("\n");
}
int main()
{
	TestQueue();
	return 0;
}

到此這篇關(guān)于C語言超詳細講解隊列的實現(xiàn)及代碼的文章就介紹到這了,更多相關(guān)C語言 隊列的實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言數(shù)組和指針,內(nèi)存之間的關(guān)系

    C語言數(shù)組和指針,內(nèi)存之間的關(guān)系

    這篇文章主要介紹了C語言數(shù)組和指針,內(nèi)存之間的關(guān)系,首先論證一維數(shù)組和一級指針之前的關(guān)系,我們常常使用一級指針指針的方式訪問一維數(shù)組,只有對內(nèi)存的理解到位才能理解它們直接的關(guān)系。需要的小伙伴可以參考一下
    2022-02-02
  • Qt無邊框窗口拖拽和陰影的實現(xiàn)方法

    Qt無邊框窗口拖拽和陰影的實現(xiàn)方法

    這篇文章主要給大家介紹了關(guān)于Qt無邊框窗口拖拽和陰影的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-11-11
  • C/C++的內(nèi)存管理你了解嘛

    C/C++的內(nèi)存管理你了解嘛

    這篇文章主要為大家介紹了C/C++的內(nèi)存管理,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • C++發(fā)送郵件實現(xiàn)代碼

    C++發(fā)送郵件實現(xiàn)代碼

    這篇文章主要為大家詳細介紹了C++發(fā)送郵件的實現(xiàn)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • C語言實現(xiàn)簡易學生成績管理系統(tǒng)

    C語言實現(xiàn)簡易學生成績管理系統(tǒng)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)簡易學生成績管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • Windows 環(huán)境下使用 Qt 連接 MySQL

    Windows 環(huán)境下使用 Qt 連接 MySQL

    這篇文章主要介紹了Windows 環(huán)境下使用 Qt 連接 MySQL的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • 判斷機器大小端的兩種實現(xiàn)方法

    判斷機器大小端的兩種實現(xiàn)方法

    第一種方法,思路:利用指針的強制類型轉(zhuǎn)換。第二種方法,思路:利用共用體所有數(shù)據(jù)都從同一地址開始存儲。
    2013-03-03
  • 深入理解c++模板中的class與typename

    深入理解c++模板中的class與typename

    在c++Template中很多地方都用到了typename與class這兩個關(guān)鍵字,而且好像可以替換,是不是這兩個關(guān)鍵字完全一樣呢?下面這篇文章主要給大家介紹了關(guān)于c++模板中class與typename的相關(guān)資料,需要的朋友可以參考下。
    2017-07-07
  • C++實現(xiàn)圖的遍歷算法(DFS,BFS)的示例代碼

    C++實現(xiàn)圖的遍歷算法(DFS,BFS)的示例代碼

    本文給大家?guī)淼氖菆D遍歷的算法,DFS(深度優(yōu)先遍歷),BFS(廣度優(yōu)先遍歷)。這兩個算法是比較重要和常用的算法,但是在圖中的實現(xiàn)只是最基本的操作,快跟隨小編一起學習一下吧
    2022-07-07
  • C++實現(xiàn)數(shù)組中元素組合出最大值

    C++實現(xiàn)數(shù)組中元素組合出最大值

    這篇文章主要介紹了C++實現(xiàn)數(shù)組中元素組合出最大值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-05-05

最新評論

县级市| 涡阳县| 贵德县| 济源市| 海城市| 大埔区| 霍林郭勒市| 大厂| 景泰县| 安龙县| 祁门县| 平阳县| 五台县| 勃利县| 松阳县| 高密市| 南和县| 博湖县| 庄浪县| 陆河县| 县级市| 咸阳市| 申扎县| 嫩江县| 梁河县| 偏关县| 奉节县| 大名县| 宾川县| 库伦旗| 宁南县| 临湘市| 商都县| 鸡西市| 霍邱县| 甘孜县| 乌苏市| 苗栗县| 贞丰县| 梁河县| 包头市|