數據結構代碼實現之隊列的鏈表實現(C/C++)


上班閑着無聊,一直想着要開始寫博客,但又不知道寫什么。最近又回顧了下數據結構的知識,那就從數據結構開始吧。

前言

關於C語言結構體的知識以及隊列的特性請讀者自行了解,此處不做過多解釋,嘻嘻。

同時此篇文章僅僅是關於隊列的鏈表實現。

第一步:結構體編寫

我們首先分析一下隊列的特征:先進先出,隊尾插入,隊頭刪除,暫時想到的就這么多。

首先,對於鏈表的節點結構體的內容,我們首先想到的是它有一個值,還有一個指向下

一個節點的指針(鏈表相關知識請讀者自行了解),那么它的結構體可實現如下:

1 typedef struct Qnode{
2     int data;
3     struct Qnode *next;
4 };

映射到圖形,其是這樣的結構:

接下來,要讓這種節點實現隊列的特性,我們可以再建立一個結構體,該結構體有一個指向隊頭節點的指針和一個指向隊尾節點的指針,那么它的實現如下:

1 typedef struct LQueue{
2     Qnode *front;
3     Qnode *rear;
4 };

其中,front指針指向隊頭,rear指針指向隊尾(注意,該指針是指向Qnode類型的指針)

映射到圖形,其是這樣的結構:

好了,結構體編寫工作到這里就完成了,下面開始下一步工作。

第二步,隊列的方法分析及實現

一個隊列有哪些方法呢,根據前面提到的特性,首先要有插入和刪除的方法,我們可以定義插入操作為入隊(書上也是這么說的),刪除操作為出隊,這兩個操作應該是隊列里最基本的。接下來,初始化隊列的方法也是尤其必要的。然后,為了測試方便,還可以定義一個獲取隊列的長度,隊列是否為空,獲取隊頭元素值,獲取隊尾元素值以及打印隊列所有節點數據的方法。下面是對這些方法的實現。

初始化方法:void initQueue(LQueue *q);

方法描述:將創建的隊列結構(通過參數傳入該方法)的隊頭和隊尾指針都指向一個動態生成的Qnode節點,代碼如下:

1 void initQueue(LQueue *q){
2     q->front = q->rear = (Qnode *)malloc(sizeof(Qnode));
3     q->front->next = NULL;
4 }

當創建了一個隊列變量,然后調用該方法時:

代碼:

1     LQueue L;
2     initQueue(&L);

內存空間如圖:

判斷隊列是否為空方法:int empty(LQueue *t);

該方法很簡單,不做過多描述,代碼如下:

int empty(LQueue *t){
    return t->front->next == t->rear;
}

 

入隊方法:void push(LQueue *t, int x);

方法描述:通過動態生成一個Qnode節點,然后將x賦值給該節點的data值,再將該節點插入到隊列中,代碼如下:

1 void push(LQueue *t, int x){
2     Qnode *s = (Qnode *)malloc(sizeof(Qnode));
3     s->data = x;
4     s->next = NULL;
5     t->rear->next = s;
6     t->rear = s;
7 }

代碼解釋:

  第2行:動態生成一個Qnode節點,讓指針s指向它;

  第3行:將傳入的x值賦值給生成的節點(s所指向)的data值;

  第4行:將s所指節點的next指針置為空;

  第5行:將隊列的隊尾指針的next指針指向s所指節點;

  第6行:再將隊尾指針指向s節點,完成push操作。

不懂的讀者希望能自行畫圖幫助理解,其實圖一畫出來就一目了然了。

出隊方法:void pop(LQueue *t);

方法描述:使用該方法時,首先應判斷隊列是否為空,為空則退出,不進行出隊操作。如果隊列不空,則首先定義一個Qnode類型指針q,讓q指向隊頭節點的下一個節點(因為隊頭節點僅作為隊頭,不存儲值),把隊頭去掉的話,就是頭節點啦。然后讓隊頭節點的next指針指向q所指節點的下一個節點,再釋放掉q所指節點(q所指節點即為要出隊的節點),代碼如下:

1 void pop(LQueue *t){
2     if(empty(t)){
3         cout << "LQueue is empty,can't pop.\n";
4         return;
5     }
6     Qnode *q = t->front->next;
7     t->front->next = q->next;
8     free(q);
9 }

代碼解釋:

  第2-5行:判斷隊列是否為空,若為空則打印提示消息后退出,不進行出隊操作;

  第6行:定義一個指針q,使其指向隊頭節點的next指針所指向的節點;(前面已經解釋了,其實就是指向隊頭節點)

  第7行:讓隊頭節點的next指針指向q的next指針所指向的節點;

  第8行:釋放掉q所指的節點的內存,完成出隊操作;

還是那句話,畫圖!一步一步理解。

獲取隊頭節點的值方法:int getFront(LQueue *t);

該方法很簡單,不做過多描述,代碼如下:

1 int getFront(LQueue *t){
2     return t->front->next->data;
3 }

獲取隊尾節點的值方法:int getRear(LQueue *t);

該方法很簡單,不做過多描述,代碼如下: 

1 int getRear(LQueue *t){
2     return t->rear->data;
3 }

獲取隊列長度的方法:int getSize(LQueue *t);

方法描述:使用一個指向頭結點的指針,不斷遍歷,每遍歷一次,計數器加1,當該指針指向空時,遍歷完成,返回該計數器,代碼如下:

1 int getSize(LQueue *t){
2     Qnode *q = t->front->next;
3     int k = 0;
4     while(q){
5         k++;
6         q = q->next;
7     }
8     return k;
9 }

代碼解釋:

  第2行:定義一個指向隊頭節點的指針q;

  第3行:定義一個計數器k;

  第4-7行:該代碼為,當q不指向NULL時,k+1,然后q指向下一個節點,繼續循環判斷。

  第8行:當循環結束時,返回該計數器k,即為隊列的長度。

打印隊列所有值方法:void printQueue(LQueue *t);

方法描述,定義一個指向Qnode類型的指針,進行遍歷,每遍歷一個節點,打印該節點,然后繼續遍歷下一節點,代碼如下:

1 void printQueue(LQueue *t){
2     Qnode *q = t->front->next;
3     while(q){
4         cout << q->data << " ";
5         q = q->next;
6     }
7     cout << "\n";
8 }

該代碼比較簡單,不做過多解釋。

好了,方法至此已全部完成,接下來,就可以通過main函數進行測試了。

第三步:編寫main方法測試運行

完整代碼如下,親測可用,希望各位新入坑的朋友多多敲代碼練習哦:

  1 #include <iostream>
  2 using namespace std;
  3 
  4 typedef struct Qnode{
  5     int data;
  6     struct Qnode *next;
  7 };
  8 
  9 typedef struct LQueue{
 10     Qnode *front;
 11     Qnode *rear;
 12 };
 13 
 14 void initQueue(LQueue *q){
 15     q->front = q->rear = (Qnode *)malloc(sizeof(Qnode));
 16     q->front->next = NULL;
 17 }
 18 
 19 int empty(LQueue *t){
 20     return t->front->next == t->rear;
 21 }
 22 
 23 void push(LQueue *t, int x){
 24     Qnode *s = (Qnode *)malloc(sizeof(Qnode));
 25     s->data = x;
 26     s->next = NULL;
 27     t->rear->next = s;
 28     t->rear = s;
 29 }
 30 
 31 void pop(LQueue *t){
 32     if(empty(t)){
 33         cout << "LQueue is empty,can't pop.\n";
 34         return;
 35     }
 36     Qnode *q = t->front->next;
 37     t->front->next = q->next;
 38     free(q);
 39     if(t->rear == NULL)
 40         t->rear = t->front;
 41 }
 42 
 43 int getFront(LQueue *t){
 44     return t->front->next->data;
 45 }
 46 
 47 int getRear(LQueue *t){
 48     return t->rear->data;
 49 }
 50 
 51 int getSize(LQueue *t){
 52     Qnode *q = t->front->next;
 53     int k = 0;
 54     while(q){
 55         k++;
 56         q = q->next;
 57     }
 58     return k;
 59 }
 60 
 61 void printQueue(LQueue *t){
 62     Qnode *q = t->front->next;
 63     while(q){
 64         cout << q->data << " ";
 65         q = q->next;
 66     }
 67     cout << "\n";
 68 }
 69 int main(){
 70     LQueue L;
 71     initQueue(&L);
 72     cout << "Push data to Queue...\n";
 73     push(&L,2);
 74     push(&L,5);
 75     push(&L,4);
 76     push(&L,3);
 77     push(&L,6);
 78     push(&L,8);
 79     push(&L,10);
 80     push(&L,11);
 81     cout << "Push finished.\n";
 82     cout << "You have pushed such data:";
 83     printQueue(&L);
 84     cout << "Pop data out of Queue...\n";
 85     pop(&L);
 86     cout << "Pop finished.\n";
 87     cout << "Now the Queue have such data:";
 88     printQueue(&L);
 89     cout << "Get Queue's front data:" << getFront(&L) << endl;
 90     cout << "Get Queue's rear data:" << getRear(&L) << endl;
 91     cout << "Get Queue's size:" << getSize(&L) << endl;
 92     pop(&L);
 93     pop(&L);
 94     pop(&L);
 95     cout << "After poped 3 times:";
 96     printQueue(&L);
 97     cout << "Judge the Queue is null or not(0 means not null,others means null):" << empty(&L) << endl;
 98     pop(&L);
 99     pop(&L);
100     pop(&L);
101     pop(&L);
102     cout << "After poped 4 times:";
103     printQueue(&L);
104     cout << "Judge the Queue is null or not(0 means not null,others means null):" << empty(&L) << endl;
105 
106     return 0;
107 }

人生中的第一篇博客,寫的不好還請海涵~~祝大家生活愉快~~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM