數據結構學習總結 棧和隊列

一,順序棧的基本操做
            同 順序表鏈表同樣,棧也是用來存儲邏輯關係爲 "一對一" 數據的線性存儲結構,如  1 所示。
          
                      棧存儲結構示意圖
                                                              圖 1 棧存儲結構示意圖
  從圖 1 咱們看到,棧存儲結構與以前所學的線性存儲結構有所差別,這緣於棧對數據 "存" 和 "取" 的過程有特殊的要求:
  1,棧只能從表的一端存取數據,另外一端是封閉的,如圖 1 所示;

  2,在棧中,不管是存數據仍是取數據,都必須遵循"先進後出"的原則,即最早進棧的元素最後出棧。拿圖 1 的棧來講,從圖中數據的存儲狀態可判斷出,元素 1 是最早進的棧。所以,當須要從棧 中取出元素 1 時,根據"先進後出"的原則,需提早將元素 3 和元素 2 從棧中取出,而後才能成功取出元素 1。html

     所以,咱們能夠給棧下一個定義,即棧是一種只能從表的一端存取數據且遵循 "先進後出" 原則的線性存儲結構。
   一般,棧的開口端被稱爲 棧頂,封口端被稱爲 棧底
所以,棧頂元素指的就是距離棧頂最近的元素,拿圖 2 來講,棧頂元素爲元素 4;同理,棧底元素指的是位於棧最底部的元素,圖 2 中的棧底元素爲元素 1。
    
                       棧頂和棧底
                        圖 2 棧頂和棧底

進棧和出棧

         基於 棧結構的特色,在實際應用中,一般只會對棧執行如下兩種操做:
  1. 向棧中添加元素,此過程被稱爲"進棧"(入棧或壓棧);
  2. 從棧中提取出指定元素,此過程被稱爲"出棧"(或彈棧);

棧的具體實現

        棧是一種 "特殊" 的線性存儲結構,所以棧的具體實現有如下兩種方式:編程

  1. 順序棧:採用順序存儲結構能夠模擬棧存儲數據的特色,從而實現棧存儲結構;
  2. 鏈棧:採用鏈式存儲結構實現棧結構;
 兩種實現方式的區別,僅限於數據元素在實際物理空間上存放的相對位置,順序棧底層採用的是 數組,鏈棧底層採用的是鏈表。有關順序棧和鏈棧的具體實現會在後續章節中做詳細講解。

棧的應用

基於棧結構對數據存取採用 "先進後出" 原則的特色,它能夠用於實現不少功能。

例如,咱們常用瀏覽器在各類網站上查找信息。假設先瀏覽的頁面 A,而後關閉了頁面 A 跳轉到頁面 B,隨後又關閉頁面 B 跳轉到了頁面 C。而此時,咱們若是想從新回到頁面 A,有兩個選擇:
  • 從新搜索找到頁面 A;
  • 使用瀏覽器的"回退"功能。瀏覽器會先回退到頁面 B,然後再回退到頁面 A。
  瀏覽器 "回退" 功能的實現,底層使用的就是棧存儲結構。當你關閉頁面 A 時,瀏覽器會將頁面 A 入棧;一樣,當你關閉頁面 B 時,瀏覽器也會將 B入棧。所以,當你執行回退操做時,纔會首先看到的是頁面 B,而後是頁面 A,這是棧中數據依次出棧的效果。

不只如此,棧存儲結構還能夠幫咱們檢測代碼中的 括號匹配問題。多數編程語言都會用到括號(小括號、中括號和大括號),括號的錯誤使用(一般是丟右括號)會致使程序編譯錯誤,而不少開發工具中都有檢測代碼是否有編輯錯誤的功能,其中就包含檢測代碼中的括號匹配問題,此功能的底層實現使用的就是棧結構。

同時,棧結構還能夠實現數值的 進制轉換功能。例如,編寫程序實現從十進制數自動轉換成二進制數,就可使用棧存儲結構來實現。

以上也僅是棧應用領域的冰山一角,這裏再也不過多舉例。在後續章節的學習中,咱們會大量使用到棧結構。
接下來,咱們學習如何實現順序棧和鏈棧,以及對棧中元素進行入棧和出棧的操做。
      順序 ,即用 順序表實現棧存儲結構。經過前面的學習咱們知道,使用棧存儲結構操做數據元素必須遵照 "先進後出" 的原則,本節就 "如何使用順序表模擬棧以及實現對棧中數據的基本操做(出棧和入棧)" 給你們作詳細介紹。
      若是你仔細觀察順序表(底層實現是 數組)和棧結構就會發現,它們存儲數據的方式高度類似,只不過棧對數據的存取過程有特殊的限制,而順序表沒有。
 例如,咱們先使用順序表(a 數組)存儲  {1,2,3,4},存儲狀態如  1 所示:
              順序表存儲 {1,2,3,4}
                  圖 1 順序表存儲 {1,2,3,4}
 一樣,使用棧存儲結構存儲  {1,2,3,4},其存儲狀態如圖 2 所示:
                   棧結構存儲 {1,2,3,4}
                 圖 2 棧結構存儲 {1,2,3,4}
 經過圖 1 和圖 2 的對比不難看出,使用順序表模擬棧結構很簡單,只須要將數據從 a 數組下標爲 0 的位置依次存儲便可。
 從數組下標爲 0 的模擬棧存儲數據是經常使用的方法,從其餘數組下標處存儲數據也徹底能夠,這裏只是爲了方便初學者理解。
 瞭解了順序表模擬棧存儲數據後,接下來看如何模擬棧中元素出棧的操做。因爲棧對存儲元素出棧的次序有"先進後出"的要求,若是想將圖 1 中存儲的元素 1 從棧中取出,需先將元素 四、元素 3 和元素 2 依次從棧中取出。
    這裏給出使用順序表模擬棧存儲結構經常使用的實現思路,即在順序表中設定一個實時指向棧頂元素的變量(通常命名爲 top),top 初始值爲 -1,表示棧中沒有存儲任何數據元素,及棧是"空棧"。一旦有數據元素進棧,則 top 就作 +1 操做;反之,若是數據元素出棧,top 就作 -1 操做

順序棧元素"入棧"

       好比,仍是模擬棧存儲  {1,2,3,4} 的過程。最初,棧是"空棧",即數組是空的,top 值爲初始值 -1,如圖 3 所示:

           空棧示意圖
                    圖 3 空棧示意圖
 首先向棧中添加元素 1,咱們默認數組下標爲 0 一端表示棧底,所以,元素 1 被存儲在數組 a[1] 處,同時 top 值 +1,如圖 4 所示:
            模擬棧存儲元素 1
                圖 4 模擬棧存儲元素 1
 
      採用以上的方式,依次存儲元素 二、3 和 4,最終,top 值變爲 3,如圖 5 所示:

                模擬棧存儲{1,2,3,4}
                圖 5 模擬棧存儲{1,2,3,4}

 所以,C 語言實現代碼爲:   數組

//元素elem進棧,a爲數組,top值爲當前棧的棧頂位置
int push(int* a,int top,int elem){ a[++top]=elem; return top; }

代碼中的 a[++top]=elem,等價於先執行 ++top,再執行 a[top]=elem。瀏覽器

順序棧元素"出棧"

其實,top 變量的設置對模擬數據的 "入棧" 操做沒有實際的幫助,它是爲實現數據的 "出棧" 操做作準備的。

好比,將圖 5 中的元素 2 出棧,則須要先將元素 4 和元素 3 依次出棧。須要注意的是,當有數據出棧時,要將 top 作 -1 操做。所以,元素 4 和元素 3 出棧的過程分別如圖 6a) 和 6b) 所示:
 
             數據元素出棧
                圖 6 數據元素出棧
 注意,圖 6 數組中元素的消失僅是爲了方便初學者學習,其實,這裏只須要對 top 值作 -1 操做便可,由於 top 值自己就表示棧的棧頂位置,所以 top-1 就等同於棧頂元素出棧。而且後期向棧中添加元素時,新元素會存儲在相似元素 4 這樣的舊元素位置上,將舊元素覆蓋。
 元素 4 和元素 3 所有出棧後,元素 2 才能出棧。所以,使用順序表模擬數據出棧操做的 C 語言實現代碼爲
//數據元素出棧
int pop(int * a,int top){ if (top==-1) { printf("空棧"); return -1; } printf("彈棧元素:%d\n",a[top]); top--; return top; }

代碼中的 if 語句是爲了防止用戶作 "棧中已無數據卻還要數據出棧" 的錯誤操做。代碼中,關於對棧中元素出棧操做的實現,只須要 top 值 -1 便可。編程語言

總結

經過學習順序表模擬棧中數據入棧和出棧的操做,初學者完成了對順序棧的學習,這裏給出順序棧及對數據基本操做的 C 語言完整代碼:
#include <stdio.h>
//元素elem進棧
int push(int* a,int top,int elem){ a[++top]=elem; return top; } //數據元素出棧
int pop(int * a,int top){ if (top==-1) { printf("空棧"); return -1; } printf("彈棧元素:%d\n",a[top]); top--; return top; } int main() { int a[100]; int top=-1; top=push(a, top, 1); top=push(a, top, 2); top=push(a, top, 3); top=push(a, top, 4); top=pop(a, top); top=pop(a, top); top=pop(a, top); top=pop(a, top); top=pop(a, top); return 0; }

程序輸出結果爲:ide

  

,即用 鏈表實現棧存儲結構。

鏈棧的實現思路同順序棧相似,順序棧是將數順序表數組)的一端做爲棧底,另外一端爲棧頂;鏈棧也如此,一般咱們將鏈表的頭部做爲棧頂,尾部做爲棧底,如 1 所示:函數


           鏈棧示意圖
                      圖 1 鏈棧示意圖
 將鏈表頭部做爲棧頂的一端,能夠避免在實現數據 "入棧" 和 "出棧" 操做時作大量遍歷鏈表的耗時操做。
 鏈表的頭部做爲棧頂,意味着:
  • 在實現數據"入棧"操做時,須要將數據從鏈表的頭部插入;
  • 在實現數據"出棧"操做時,須要刪除鏈表頭部的首元節點;
所以,鏈棧實際上就是一個只能採用頭插法插入或刪除數據的鏈表。

鏈棧元素入棧

例如,將元素 一、二、三、4 依次入棧,等價於將各元素採用頭插法依次添加到鏈表中,每一個數據元素的添加過程如圖 2 所示:
              鏈棧元素依次入棧過程示意圖
            圖 2 鏈棧元素依次入棧過程示意圖
C語言實現代碼爲:
//鏈表中節點結構
typedef struct lineStack{ int data; struct lineStack* next; }; //壓棧 stack 當前鏈棧 a 入棧元素
lineStack* push(lineStack* stack,int a) { //建立存儲新元素的節點
    lineStack* temp = (lineStack*)malloc(sizeof(lineStack)); temp->data = a; //新節點與頭節點創建關聯
    temp->next = stack; //更新頭指針指向
    stack = temp; return stack; }

鏈棧元素出棧

例如,圖 2e) 所示的鏈棧中,若要將元素 3 出棧,根據"先進後出"的原則,要先將元素 4 出棧,也就是從鏈表中摘除,而後元素 3 才能出棧,整個操做過程如圖 3 所示:工具


       鏈棧元素出棧示意圖
            圖 3 鏈棧元素出棧示意圖
所以,實現棧頂元素出鏈棧的 C 語言實現代碼爲:
//棧頂元素出棧的實現函數
lineStack* pop(lineStack* stack) { if (stack) { //聲明一個新指針指向棧頂節點
        lineStack *p = stack; //更新頭節點
        stack = stack->next; printf("出棧元素:%d \n",p->data); if (stack) { printf("新棧頂元素:%d\n",stack->data); } else { printf("棧已空\n"); } free(p); } else { printf("棧內沒有元素\n"); return stack; } return stack;

代碼中經過使用 if 判斷語句,避免了用戶執行"棧已空卻還要數據出棧"錯誤操做。學習

總結

本節,經過採用頭插法操做數據的單鏈表實現了鏈棧結構,這裏給出鏈棧及基本操做的C語言完整代碼:
#include<stdlib.h> #include<stdio.h>
//鏈表中節點結構
typedef struct lineStack{ int data; struct lineStack* next; }; //壓棧 stack 當前鏈棧 a 入棧元素
lineStack* push(lineStack* stack,int a) { //建立存儲新元素的節點
    lineStack* temp = (lineStack*)malloc(sizeof(lineStack)); temp->data = a; //新節點與頭節點創建關聯
    temp->next = stack; //更新頭指針指向
    stack = temp; return stack; } //棧頂元素出棧的實現函數
lineStack* pop(lineStack* stack) { if (stack) { //聲明一個新指針指向棧頂節點
        lineStack *p = stack; //更新頭節點
        stack = stack->next; printf("出棧元素:%d ",p->data); if (stack) { printf("新棧頂元素:%d\n",stack->data); } else { printf("棧已空\n"); } free(p); } else { printf("棧內沒有元素\n"); return stack; } return stack; } int main() { lineStack * stack = NULL; stack = push(stack, 1); stack = push(stack, 2); stack = push(stack, 3); stack = push(stack, 4); stack = pop(stack); stack = pop(stack); stack = pop(stack); stack = pop(stack); stack = pop(stack); return 0; }
View Code

運行結果:開發工具

 二,順序表及隊列的實現

         隊列,和 同樣,也是一種對數據的"存"和"取"有嚴格要求的線性存儲結構。
  與棧結構不一樣的是,隊列的兩端都"開口",要求數據只能從一端進,從另外一端出,如  1 所示:
 
             隊列存儲結構
                  圖 1 隊列存儲結構
一般,稱進數據的一端爲 "隊尾",出數據的一端爲 "隊頭",數據元素進隊列的過程稱爲 "入隊",出隊列的過程稱爲 "出隊"。
 不只如此,隊列中數據的進出要遵循 "先進先出" 的原則,即最早進隊列的數據元素,一樣要最早出隊列。拿圖 1 中的隊列來講,從數據在隊列中的存儲狀態能夠分析出,元素 1 最早進隊,其次是元素 2,最後是元素 3。此時若是將元素 3 出隊,根據隊列 "先進先出" 的特色,元素 1 要先出隊列,元素 2 再出隊列,最後才輪到元素 3 出隊列。
 棧和隊列不要混淆,棧結構是一端封口,特色是"先進後出";而隊列的兩端全是開口,特色是"先進先出"。
 所以,數據從表的一端進,從另外一端出,且遵循 "先進先出" 原則的線性存儲結構就是隊列。

隊列的實現

 隊列存儲結構的實現有如下兩種方式:
  1. 順序隊列:在順序表的基礎上實現的隊列結構;
  2. 鏈隊列:在鏈表的基礎上實現的隊列結構;
 二者的區別僅是順序表和鏈表的區別,即在實際的物理空間中,數據集中存儲的隊列是順序隊列,分散存儲的隊列是鏈隊列。
 
隊列的實際應用
實際生活中,隊列的應用隨處可見,好比排隊買 XXX、醫院的掛號系統等,採用的都是隊列的結構。

拿排隊買票來講,全部的人排成一隊,先到者排的就靠前,後到者只能從隊尾排隊等待,隊中的每一個人都必須等到本身前面的全部人所有買票成功並從隊頭出隊後,才輪到本身買票。這就不是典型的隊列結構嗎?
明白了什麼是隊列,接下來開始系統地學習順序隊列和鏈隊列。
順序 隊列,即採用 順序表模擬實現的隊列結構。
     咱們知道,隊列具備如下兩個特色:
  1. 數據從隊列的一端進,另外一端出;
  2. 數據的入隊和出隊遵循"先進先出"的原則;
所以,只要使用順序表按以上兩個要求操做數據,便可實現順序隊列。首先來學習一種最簡單的實現方法。

順序隊列簡單實現

因爲順序隊列的底層使用的是 數組,所以需預先申請一塊足夠大的內存空間初始化順序隊列。除此以外,爲了知足順序隊列中數據從隊尾進,隊頭出且先進先出的要求,咱們還須要定義兩個指針(top 和 rear)分別用於指向順序隊列中的隊頭元素和隊尾元素,如  1 所示:
                       順序隊列實現示意圖
                          圖 1 順序隊列實現示意圖
   因爲順序隊列初始狀態沒有存儲任何元素,所以 top 指針和 rear 指針重合,且因爲順序隊列底層實現靠的是數組,所以 top 和 rear 其實是兩個變量,它的值分別是隊頭元素和隊尾元素所在數組位置的下標。
在圖 1 的基礎上,當有數據元素進隊列時,對應的實現操做是將其存儲在指針 rear 指向的數組位置,而後 rear+1;當須要隊頭元素出隊時,僅需作 top+1 操做。
 
例如,在圖 1 基礎上將  {1,2,3,4} 用順序隊列存儲的實現操做如圖 2 所示:
                 數據進順序隊列的過程實現示意圖
                      圖 2 數據進順序隊列的過程實現示意圖
在圖 2 基礎上,順序隊列中數據出隊列的實現過程如圖 3 所示:
 
               數據出順序隊列的過程示意圖
                          圖 3 數據出順序隊列的過程示意圖
 所以,使用順序表實現順序隊列最簡單方法的 C 語言實現代碼爲:
#include <stdio.h>
int enQueue(int *a,int rear,int data){ a[rear]=data; rear++; return rear; } void deQueue(int *a,int front,int rear){ //若是 front==rear,表示隊列爲空
    while (front!=rear) { printf("出隊元素:%d\n",a[front]); front++; } } int main() { int a[100]; int front,rear; //設置隊頭指針和隊尾指針,當隊列中沒有元素時,隊頭和隊尾指向同一塊地址
    front=rear=0; //入隊
    rear=enQueue(a, rear, 1); rear=enQueue(a, rear, 2); rear=enQueue(a, rear, 3); rear=enQueue(a, rear, 4); //出隊
 deQueue(a, front, rear); return 0; }

程序輸出結果:

出隊元素:1
出隊元素:2
出隊元素:3
出隊元素:4

此方法存在的問題

先來分析如下圖 2b) 和圖 3b)。圖 2b) 是全部數據進隊成功的示意圖,而圖 3b) 是全部數據所有出隊後的示意圖。經過對比兩張圖,你會發現,指針 top 和 rear 重合位置指向了  a[4] 而再也不是 a[0]。也就是說,整個順序隊列在數據不斷地進隊出隊過程當中,在順序表中的位置不斷後移。

順序隊列總體後移形成的影響是:
  • 順序隊列以前的數組存儲空間將沒法再被使用,形成了空間浪費;
  • 若是順序表申請的空間不足夠大,則直接形成程序中數組 a 溢出,產生溢出錯誤;
爲了不以上兩點,我建議初學者使用下面的方法實現順序隊列。

順序隊列另外一種實現方法

既然明白了上面這種方法的弊端,那麼咱們能夠試着在它的基礎上對其改良。
  爲了解決以上兩個問題,可使用巧妙的方法將順序表打形成一個環狀表,如圖 4 所
                環狀順序隊列
                    圖 4 環狀順序隊列
圖 4 只是一個想象圖,在真正的實現時,不必真建立這樣一種結構,咱們仍是使用以前的順序表,也仍是使用以前的程序,只須要對其進行一點小小的改變:
 
#include <stdio.h>
#define max 5//表示順序表申請的空間大小
int enQueue(int *a,int front,int rear,int data){ //添加判斷語句,若是rear超過max,則直接將其從a[0]從新開始存儲,若是rear+1和front重合,則表示數組已滿
    if ((rear+1)%max==front) { printf("空間已滿"); return rear; } a[rear%max]=data; rear++; return rear; } int  deQueue(int *a,int front,int rear){ //若是front==rear,表示隊列爲空
    if(front==rear%max) { printf("隊列爲空"); return front; } printf("%d ",a[front]); //front再也不直接 +1,而是+1後同max進行比較,若是=max,則直接跳轉到 a[0]
    front=(front+1)%max; return front; } int main() { int a[max]; int front,rear; //設置隊頭指針和隊尾指針,當隊列中沒有元素時,隊頭和隊尾指向同一塊地址
    front=rear=0; //入隊
    rear=enQueue(a,front,rear, 1); rear=enQueue(a,front,rear, 2); rear=enQueue(a,front,rear, 3); rear=enQueue(a,front,rear, 4); //出隊
    front=deQueue(a, front, rear); //再入隊
    rear=enQueue(a,front,rear, 5); //再出隊
    front=deQueue(a, front, rear); //再入隊
    rear=enQueue(a,front,rear, 6); //再出隊
    front=deQueue(a, front, rear); front=deQueue(a, front, rear); front=deQueue(a, front, rear); front=deQueue(a, front, rear); return 0; }

程序運行結果:

 1 2 3 4 5 6
 使用此方法須要注意的是,順序隊列在判斷數組是否已滿時,出現下面狀況:
  • 當隊列爲空時,隊列的頭指針等於隊列的尾指針;
  • 當數組滿員時,隊列的頭指針等於隊列的尾指針;
順序隊列的存儲狀態不一樣,可是判斷條件相同。爲了對其進行區分,最簡單的解決辦法是:犧牲掉數組中的一個存儲空間,判斷數組滿員的條件是:尾指針的下一個位置和頭指針相遇,就說明數組滿了,即程序中第 5 行所示。
 
鏈式隊列,簡稱"鏈隊列",即便用鏈表實現的隊列存儲結構。
鏈式隊列的實現思想同 順序隊列相似,只需建立兩個指針(命名爲 top 和 rear)分別指向鏈表中隊列的隊頭元素和隊尾元素,如  1 所示:
                鏈式隊列的初始狀態
                      圖 1 鏈式隊列的初始狀態
圖 1 所示爲鏈式隊列的初始狀態,此時隊列中沒有存儲任何數據元素,所以 top 和 rear 指針都同時指向頭節點。
 在建立鏈式隊列時,強烈建議初學者建立一個帶有頭節點的鏈表,這樣實現鏈式隊列會更簡單。
  由此,咱們能夠編寫出建立鏈式隊列的 C 語言實現代碼爲:
//鏈表中的節點結構
typedef struct QNode{ int data; struct QNode * next; }QNode; //建立鏈式隊列的函數
QNode * initQueue(){ //建立一個頭節點
    QNode * queue=(QNode*)malloc(sizeof(QNode)); //對頭節點進行初始化
    queue->next=NULL; return queue; }

鏈式隊列數據入隊

鏈隊隊列中,當有新的數據元素入隊,只需進行如下 3 步操做:

  1. 將該數據元素用節點包裹,例如新節點名稱爲 elem;
  2. 與 rear 指針指向的節點創建邏輯關係,即執行 rear->next=elem;
  3. 最後移動 rear 指針指向該新節點,即 rear=elem;

由此,新節點就入隊成功了。

例如,在圖 1 的基礎上,咱們依次將 {1,2,3} 依次入隊,各個數據元素入隊的過程如圖 2 所示:

 
               {1,2,3} 入鏈式隊列
                        圖 2 {1,2,3} 入鏈式隊列
數據元素入鏈式隊列的 C 語言實現代碼爲:    
QNode* enQueue(QNode * rear,int data){ //一、用節點包裹入隊元素
    QNode * enElem=(QNode*)malloc(sizeof(QNode)); enElem->data=data; enElem->next=NULL; //二、新節點與rear節點創建邏輯關係
    rear->next=enElem; //三、rear指向新節點
    rear=enElem; //返回新的rear,爲後續新元素入隊作準備
    return rear; }

鏈式隊列數據出隊

當鏈式隊列中,有數據元素須要出隊時,按照 "先進先出" 的原則,只需將存儲該數據的節點以及它以前入隊的元素節點按照原則依次出隊便可。這裏,咱們先學習如何將隊頭元素出隊。

鏈式隊列中隊頭元素出隊,須要作如下 3 步操做:

  1. 經過 top 指針直接找到隊頭節點,建立一個新指針 p 指向此即將出隊的節點;
  2. 將 p 節點(即要出隊的隊頭節點)從鏈表中摘除;
  3. 釋放節點 p,回收其所佔的內存空間;


例如,在圖 2b) 的基礎上,咱們將元素 1 和 2 出隊,則操做過程如圖 3 所示

 
                 鏈式隊列中數據元素出隊
                      圖 3 鏈式隊列中數據元素出隊

鏈式隊列中隊頭元素出隊的 C 語言實現代碼爲:
 
void DeQueue(QNode * top,QNode * rear){ if (top->next==NULL) { printf("隊列爲空"); return ; } // 一、
    QNode * p=top->next; printf("%d",p->data); top->next=p->next; if (rear==p) { rear=top; } free(p); }

注意,將隊頭元素作出隊操做時,需提早判斷隊列中是否還有元素,若是沒有,要提示用戶沒法作出隊操做,保證程序的健壯性。

總結

經過學習鏈式隊列最基本的數據入隊和出隊操做,咱們能夠就實際問題,對以上代碼作適當的修改。

前面在學習順序隊列時,因爲順序表的侷限性,咱們在順序隊列中實現數據入隊和出隊的基礎上,又對實現代碼作了改進,令其可以充分利用數組中的空間。鏈式隊列就不須要考慮空間利用的問題,由於鏈式隊列自己就是實時申請空間。所以,這能夠算做是鏈式隊列相比順序隊列的一個優點。

這裏給出鏈式隊列入隊和出隊的完整 C 語言代碼爲:

 
#include <stdio.h> #include <stdlib.h> typedef struct QNode{ int data; struct QNode * next; }QNode; QNode * initQueue(){ QNode * queue=(QNode*)malloc(sizeof(QNode)); queue->next=NULL; return queue; } QNode* enQueue(QNode * rear,int data){ QNode * enElem=(QNode*)malloc(sizeof(QNode)); enElem->data=data; enElem->next=NULL; //使用尾插法向鏈隊列中添加數據元素
    rear->next=enElem; rear=enElem; return rear; } QNode* DeQueue(QNode * top,QNode * rear){ if (top->next==NULL) { printf("\n隊列爲空"); return rear; } QNode * p=top->next; printf("%d ",p->data); top->next=p->next; if (rear==p) { rear=top; } free(p); return rear; } int main() { QNode * queue,*top,*rear; queue=top=rear=initQueue();//建立頭結點 //向鏈隊列中添加結點,使用尾插法添加的同時,隊尾指針須要指向鏈表的最後一個元素
    rear=enQueue(rear, 1); rear=enQueue(rear, 2); rear=enQueue(rear, 3); rear=enQueue(rear, 4); //入隊完成,全部數據元素開始出隊列
    rear=DeQueue(top, rear); rear=DeQueue(top, rear); rear=DeQueue(top, rear); rear=DeQueue(top, rear); rear=DeQueue(top, rear); return 0; }

程序運行結果爲:

 

1 2 3 4
隊列爲空

相關文章
相關標籤/搜索