日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构 - 队列简介 及 1个简单的c语言链式队列代码实现

發布時間:2025/3/20 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构 - 队列简介 及 1个简单的c语言链式队列代码实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 隊列的定義

???????????????? 所謂隊列(queue)就是一種能實現"先進先出"的一種線性存儲結構.

???????????????? 跟棧有點類似,? 例如棧只有1個出入口, 任何元素進入或者離開棧都必須經過同1個出入口(棧頂), 所以棧能實現"先入后出"的效果.

???????????????

????????????????? 隊列同樣有出入口, 只不過出入口分別位于隊列的兩端, 元素只能從入口進入隊列,? 而且只能從另一端的出口離開隊列, 在隊列中間里的元素是不允許插入或刪除操作的, 所以先進入隊列的元素肯定會比后進入的元素先離開隊列, 就是所謂的"先進先出"了.


????????????????? 舉個例子, 例如現實中排隊買票就是1個隊列,? 1個人只能從隊伍的尾部進入隊列, 從隊伍的前部(買票窗口)買票離開隊列, 中間插隊是不允許的.


2. 隊列的分類

?????????????????? 就如棧可以分成動態棧和靜態棧一樣.

?????????????????? 隊列也可以分成靜態隊列和鏈式隊列.

???????????????

?????????????????? 所謂靜態隊列就是用數組(連續內存) 作為內核的隊列.

?????????????????? 而鏈式隊列就是以鏈表為內核的隊列了.

?

?????????????????? 下面會簡介鏈式隊列, 而且是單鏈表的鏈式隊列.


3. 鏈式隊列(單鏈表)的大概結構

?畫個圖便于理解:



如上圖,? 我們會將1個單鏈表的首節點作為隊列的前端(front), 就是隊列的出口啦.??? 而會將單鏈表的尾節點作為隊列的尾端(Rear), 就是隊列的入口.


而我們會定義兩個指針,? Front指針來存放隊列出口元素的地址,?? Rear指針來存放隊列入口元素的地址.


之所以這樣設定是為了方便出列操作,? 如上圖,? 當節點0 要出列時, 0 作為1個首節點,? 出列后Front指針就必須指向出列元素的下1個節點地址(節點1),? 而這個地址恰好保存于節點0的尾部指針中啊.?????假如在單鏈表的尾部出列, 如上圖, 加入節點4出列后, Front就必須指向節點3,? 但是節點3的尾部指針指向節點4,? 而根據節點4是找不到節點4上1個元素的地址的, 只能遍歷鏈表啊.


而在尾節點入列同樣方便, 如上圖,? 當節點4入列時, 只需要將隊列原來的入口元素(Rear指針)的尾部地址指向入列節點, 然后 Rear指針指向這個新的入口元素!


上面就是1個最基本的鏈式隊列結構, 但是有1個弊端, 就是當這個隊列為空(所有元素出列后), 這個鏈表就消失了, 再入列時就無從下手!


所以實際操作我們會給在隊列的前部(出口)加上1個不存放實際數據的頭節點, 做為列表的出口, 這個頭節點指向隊列的真正的出口元素(pHead->pnext). 這樣當隊列所有元素出列后, 隊列的Rear指針就手動指向不存放實際數據的頭節點, 這樣的話我們會認為這個隊列是空隊列.(pHead == pRear)


如下圖:


4. 一個簡單的鏈式隊列的C語言代碼實現

4.1 首先就是編寫1個頭文件

在這個頭文件里我們會定義兩個結構體,? 1個是對應于隊列的元素的, 所以這個結構體具有1個pNext 指針成員。 另1個結構體是對應于鏈式隊列的, ?具有4個成員, 分別是: pHead ?頭結點地址 pRear ? 存放入口元素的地址 len ? ? ? ? 存放鏈表的長度信息 is_inited 用于判斷鏈表結構體是否被初始化(里面的指針成員是否野指針)

此外, 這個頭文件也會生命一些算法函數, 別的文件引用這個頭文件, 就可以使用這些函數了。
代碼如下: /** linkqueue1.h** Created on: 2013-4-15* Author: gateman*/ #include <bool_me.h> #ifndef __LINKQUEUE1_H_ #define __LINKQUEUE1_H_struct person_linkqueue1{int id;char name[16];struct person_linkqueue1 * pNext;};typedef struct person_linkqueue1 PERSON_LQ;struct linkqueue1_person{PERSON_LQ * pHead;PERSON_LQ * pRear;int len;BOOL is_inited;};typedef struct linkqueue1_person LQPERSON;//create a new node with dynamic memory assignedPERSON_LQ * person_lq_new(int id, char * pname);//print the information of a nodevoid person_lq_print(PERSON_LQ * pnode);//create a stuck with dynamic linklistLQPERSON * lqperson_new(void);//judge whether the link_queue is emptyBOOL lq_is_empty(LQPERSON * pLq);//add an element into the queuevoid lq_Enqueue(LQPERSON * pLq, PERSON_LQ * pnode);//remove an element from the queue, and get the elementBOOL lq_Dequeue(LQPERSON * pLq, PERSON_LQ ** pOutput);//traverse the queue to print all the elementsvoid lq_print(LQPERSON * pLq);//put out and free all the elements from the queuevoid lq_clear(LQPERSON * pLq);//free all the elements, and free the queuevoid lq_free(LQPERSON * pLq);#endif /* LINKQUEUE1_H_ */

下面會用列出上面聲明的函數定義代碼.


4.2 建立1個新節點(元素)函數 PERSON_LQ * person_lq_new(int id, char * pname)

這個函數作用就是動態分配1個新的內存給1個節點結構體, 既然是動態分配的, 那么這個節點很容易被其他函數訪問。? 而且必要時也可以手動釋放。

邏輯步驟如下:
1. 新建1個節點類型指針.? 并動態分配一段內存.
2. 如果分配不成功,? 退出程序
3. 設置參數傳入的成員值(id, name)
4. 尾部指針設成NULL
5. 返回這個指針



代碼如下:
PERSON_LQ * person_lq_new(int id, char * pname){PERSON_LQ * pnode = (PERSON_LQ *)malloc(sizeof(PERSON_LQ));if (NULL == pnode){base_error("fail to assign memory to a new node!");}pnode->id = id;strncpy(pnode->name, pname+0, 15);pnode->pNext=NULL;return pnode; }


4.3 打印1個節點的信息 void person_lq_print(PERSON_LQ * pnode)

這個不講解了, 很簡單

代碼如下:

//print the information of a node void person_lq_print(PERSON_LQ * pnode){printf("id is %d, name is %s\n",pnode->id, pnode->name); }


4.4 新建并初始化1個鏈式隊列 LQPERSON * lqperson_new(void)

這個函數就是動態分配1段內存給1個鏈式隊列, 并執行初始化, 最后返回這個結構體指針


步驟:

1. 新建1個鏈式隊列結構體指針, 并動態分配1個內存

2. 若分配內存失敗, 退出程序

3. 初始化鏈式隊列的 pHead 頭節點成員( 利用上面的 person_lq_new函數)

4. pRear 成員指向 pHead (代表空隊列)

5. len長度設為0

6. is_inited 成員設為TRUE

7. 返回鏈式隊列結構體指針


代碼如下:

//create a stuck with dynamic linklist LQPERSON * lqperson_new(void){LQPERSON * pLq = (LQPERSON *)malloc(sizeof(LQPERSON));if (NULL == pLq){base_error("fail to assign memory to a linkqueue!");}pLq->pHead = person_lq_new(-1,"Head");pLq->pRear = pLq->pHead; //empty queue;pLq->len=0;pLq->is_inited = TRUE;return pLq; }

4.5 判斷鏈式隊列是否為空? BOOL lq_is_empty(LQPERSON * pLq)

這個很簡單, 判斷 pRear 是否指向 pHead就ok了, 當然判斷len ==0 也可以..

代碼如下:

//judge whether the link_queue is empty BOOL lq_is_empty(LQPERSON * pLq){if (TRUE != pLq->is_inited){base_error("the linkqueue is not initailed yet!");}if (pLq->pRear == pLq->pHead){return TRUE;}return FALSE; }

4.6 入列函數 void lq_Enqueue(LQPERSON * pLq, PERSON_LQ * pnode)

作用就是把1個節點元素放入隊列, 邏輯并不復雜. 上面圖解過了嘛

步驟:

1.入口元素地址 pRear的尾部指針指向這個入列元素

2,pRear 指向 這個入列元素, 這個入列元素就成為新的入口元素了

3. 這個入列元素的尾部指針指向NULL

4. 鏈表長度len+1


代碼如下:

//add an element into the queue void lq_Enqueue(LQPERSON * pLq, PERSON_LQ * pnode){if (TRUE != pLq->is_inited){base_error("the linkqueue is not initailed yet!");}pLq->pRear->pNext = pnode;pLq->pRear = pnode;pnode->pNext=NULL;pLq->len++; }

4.7 出列函數 BOOL lq_Dequeue(LQPERSON * pLQ, PERSON_LQ ** pOutput)

注意這個函數, 返回值是BOOL 也就是出列函數有可能失敗, 因為如果1個空隊列, 出列就肯定失敗嘛

而且接受1個以地址傳遞的指針, 也就是指針的指針了,? 用于接受出列元素的地址.


邏輯如下:

1. 判斷是否為空隊列, 否則返回FALSE

2.? pOutput 指向出列元素(pHead 下1個元素)

3. pHead 頭節點的尾部指針指向出列元素的下1個元素,? 那個就是新的出口元素, 也就是說下次出列就輪到它啊

4. 如果出列元素是最后1個元素, 出列后 pRear 指向pHead, 代表成為1個空隊列了

5. 隊列長度len -1

6. 返回TRUE


代碼如下:

//remove an element from the queue, and get the element BOOL lq_Dequeue(LQPERSON * pLq, PERSON_LQ ** pOutput){if (TRUE != pLq->is_inited){base_error("the linkqueue is not initailed yet!");}if (TRUE == lq_is_empty(pLq)){printf("the linkqueue is empty!\n");return FALSE;}*pOutput = pLq->pHead->pNext;pLq->pHead->pNext = (*pOutput)->pNext;//if it's the last oneif(pLq->pRear == *pOutput){pLq->pRear = pLq->pHead; //empty}pLq->len--;return TRUE; }

4.8 打印1個隊列函數 lq_print(LQPERSON * pLq)

這個函數作用就是從出口開始打印隊列的存放有效數據的函數,? 就是從Front 到 Rear啦.

相當于1個遍歷,

代碼如下:

//traverse the queue to print all the elements void lq_print(LQPERSON * pLq){if (TRUE != pLq->is_inited){base_error("the linkqueue is not initailed yet!");}if (TRUE == lq_is_empty(pLq)){printf("the linkqueue is empty!\n");}PERSON_LQ * pnode = pLq->pHead;while(NULL != pnode->pNext){pnode=pnode->pNext;person_lq_print(pnode);} }

4.9 刪除所有隊列元素函數 lq_clear

當然, pRear 指向 pHead, 這樣這個隊列馬上就是1個空隊列, 但是這樣里面的節點就容易丟失, 也就是內存泄露啊

所以我們要逐個地釋放里面節點的內存, 然后才把 pRear 指向 pHead

//put out and free all the elements from the queue void lq_clear(LQPERSON * pLq){if (TRUE != pLq->is_inited){base_error("the linkqueue is not initailed yet!");}PERSON_LQ * pnode = pLq->pHead;PERSON_LQ * pnext = pnode->pNext;while(NULL != pnext){pnode = pnext;pnext = pnode->pNext;free(pnode);}pLq->pHead->pNext=NULL;pLq->pRear = pLq->pHead;pLq->len=0; }

4.9 銷毀隊列函數 lq_free

這個更簡單, 首先執行清空.

然后把頭節點的內存釋放

最后把隊列結構體釋放

代碼如下:

//free all the elements, and free the queue void lq_free(LQPERSON * pLq){lq_clear(pLq);free(pLq->pHead);free(pLq); }


4.10 寫個程序測試上面的函數

純粹測試下啦:

代碼如下:

int linkqueue1(){PERSON_LQ * pnode = person_lq_new(1,"JasonPoon111212121212");person_lq_print(pnode);free(pnode);LQPERSON * plq1 = lqperson_new();lq_Enqueue(plq1, person_lq_new(1,"Jason"));lq_Enqueue(plq1, person_lq_new(2,"Cindy"));lq_Enqueue(plq1, person_lq_new(3,"Fiana"));lq_Enqueue(plq1, person_lq_new(4,"Gateman"));lq_print(plq1);int i=0;int j=plq1->len-1;for (i=0; i < j; i++){lq_Dequeue(plq1,&pnode);printf("the out node is\n");person_lq_print(pnode);printf("\n");free(pnode);}lq_print(plq1);lq_Dequeue(plq1,&pnode);printf("the out node is\n");person_lq_print(pnode);printf("\n");free(pnode);lq_print(plq1);lq_Enqueue(plq1, person_lq_new(1,"Jason"));lq_Enqueue(plq1, person_lq_new(2,"Cindy"));lq_Enqueue(plq1, person_lq_new(3,"Fiana"));lq_Enqueue(plq1, person_lq_new(4,"Gateman"));lq_print(plq1);printf("now clear the linkqueuei!\n");lq_clear(plq1);lq_print(plq1);lq_free(plq1);printf("linkq1 done\n");return 0; }

輸出:























總結

以上是生活随笔為你收集整理的数据结构 - 队列简介 及 1个简单的c语言链式队列代码实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。