1. 程式人生 > >資料結構程式碼實現之佇列的連結串列實現(C/C++)

資料結構程式碼實現之佇列的連結串列實現(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 }

複製程式碼

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

https://www.cnblogs.com/HeZhengfa/p/HeZhengfa.html

鄭州不孕不育檢查

鄭州不孕不育

鄭州最好的不孕不育醫院

鄭州不孕不育