學習數據結構--第三章:棧和隊列(順序隊列的基本操作、循環隊列)

第三章:棧和隊列

上篇文章中我們講了 學習數據結構–第三章:棧和隊列(棧的基本操作) 下面講解隊列的基本操作。

1.隊列的基本概念

隊列(Queue) 只允許在表的 一端(隊尾) 進行插入,表的 另一端(對頭) 進行刪除操作的 線性表

在隊列中先進入隊列的元素會先出隊列即:先進先出 (FIFO)
在這裏插入圖片描述

2.隊列的基本操作

  • InitQueue(&Q) 初始化隊列,構造一個空隊列Q
  • QueueEmpty(Q) 判隊列空,若隊列Q爲空返回true,否則返回 false
  • EnQueue(&Q,x) 入隊,若隊列Q未滿,則將x加入使之成爲新的隊尾。
  • DeQueue(&q,&x) 出隊,若隊列Q非空,則刪除隊頭元素,並用x返回。
  • GetHead(Q,&x) 讀隊頭元素,若隊列Q非空則用x返回隊頭元素。
  • ClearQueue(&Q) 銷燬隊列,並釋放隊列Q佔用的內存空間。

3.隊列順序存儲結構

順序隊 採用順序存儲的隊列。

在上篇棧的文章中我們直到,棧使用一個top變量存儲棧頂的下標,用來出棧和入棧,在隊列中是否也可以使用一個top變量存儲隊頭的變量,然後操作棧呢?

答案是不行的,注意棧的出棧和入棧都只在一端進行操作,所以一個變量存儲下標完全夠了,但是隊列不同,隊列的入隊和出隊分別在兩端,所以我們需要兩個變量分別存儲入隊地址(front)和出隊地址(rear),注意:我們規定rear存儲隊尾元素的下一個位置。

在這裏插入圖片描述
隊列的定義:

#define MaxSize 50
typedef struct{
    ElemType data[MaxSize];
    int front,rear;
}SqQueue;

隊列中需要注意:

  • front指向隊頭元素,rear指向隊尾元素的下一位置(或front指向隊頭元素的前一位置,rear指向隊尾元素)
  • 平時使用中我們一般讓front指向隊頭元素,rear指向隊尾元素的下一位置
  • 初始時 front==rear==0

3.1順序隊列判空&長度&滿

判空

隊空條件:Q.front == Q.rear == 0 ???
這個判斷條件是不對的,如果入隊一個元素,接着出隊,此時rearfront都是會移動的,此時不是0但是隊列也是空的。所以說,上述條件是:不是充分必要條件,真正的條件是:Q.front == Q.rear

長度

front指向隊頭元素,rear指向隊尾元素的下一位置,故隊列的長度是:Q.rear - Q.front

隊滿

隊滿條件 Q.rear ==MaxSize ???
當隊列滿的時候,此時進行出隊操作,此時出隊的時候只是修改了front,並未修改rear,如果按照上述條件判斷,隊列是滿的,但是實際上是空的,這就是假溢出問題.
那麼怎麼解決這個問題,同時利用上剛剛出隊的那個空間呢?我們可以使用一個特殊隊列-----循環隊列

4.順序存儲的循環隊列

循環隊列 把存儲隊列的順序隊列在邏輯上視爲一個環。

在這裏插入圖片描述
改成循環隊列,將最後一個數據元素單元和第一個數據元素單元連接起來,方法就是取餘(%MaxSize)操作
在這裏插入圖片描述
front指針移動
Q.front=(Q.front + 1) % MaxSize
rear指針移動
Q.rear = (Q.rear + 1) % MaxSize
隊列長度
(Q.rear + MaxSize - Q.front) % MaxSize

4.1循環隊列判空&滿

在這裏插入圖片描述

隊列判空:Q.front == Q.rear

隊列判滿:Q.front == Q.rear

此時發現判空和判滿條件一致了,這就出現矛盾了。怎麼解決呢?

方法一:犧牲一個存儲單元

這是最常用的一種方法,具體就是,最後一個元素的位置不存儲元素,當Q.front=(Q.rear+1)%MaxSize的時候,表示隊列已經滿了。這種方法

  • 隊列判空條件不變:Q.front == Q.rear
  • 隊列判滿條件變成:Q.front=(Q.rear+1)%MaxSize

方法二:增加一個變量代表元素的個數

我們初始化一個變量:Q.size=0 。這種方法

  • 判空條件:Q.size == 0
  • 判滿條件:Q.size == MaxSize

方法三:增加tag標識

我們發現隊列爲空是因爲刪除操作導致,隊列爲滿是因爲插入操作導致,所以我們可以使用一個變量來標識隊列當前的狀態,當隊列爲空的時候對於循環隊列首先Q.front==Q.rear,此時我們標識tag=0,當隊列滿的時候首先Q.front==Q.rear,我們標識tag=1。這種方法

  • 判空條件:Q.front==Q.rear&&Q.tag == 0
  • 判滿條件:Q.front==Q.rear&&Q.tag == 1

4.2循環隊列的基本操作

初始化

void Initqueue(SqQueue &Q){
   Q.rear = Q.front = 0;
}

判空

bool isEmpty(SqQueue Q){ 
   if(Q.rear == front) {
       return true; 
   }else{
       return false;
   }

入隊

bool EnQueue(SqQueue &Q, ElemType x){
     if((Q.rear+1)%MaxSize==Q.front){//判滿
          return false;
     }
     Q.data[Q.rear] = x;
     Q.rear = (Q.rear + 1)%MaxSize;
     return true;
}

出隊

bool DeQueue(SqQueue &Q,ElemType &x){
    if(Q.rear == Q.front){//判空
        return false;
    }
    x = Q.data[Q.front];
    Q.front = (Q.front+1)%MaxSize; //隊頭指針向後移動一位
    return true;
}

5.隊列鏈式存儲結構

鏈隊 採用鏈式存儲的隊列

下面是有頭節點的鏈隊,使用front指針指向隊頭,使用rear指針指向隊尾。
在這裏插入圖片描述
隊列中每個結點的結構體

typedef struct{
    ElemType data;
    struct LinkNode *next;
}LinkNode;

鏈隊的結構體也就是隊頭和隊尾的兩個指針

typedef struct{
   LinkNode *front,*rear;
}LinkQueue;

6.鏈隊的基本操作

初始化
在這裏插入圖片描述

判空

在這裏插入圖片描述

入隊

入隊就相當於單鏈表的尾插法

在這裏插入圖片描述
出隊

出隊相當於單鏈表的刪除頭結點的操作

在這裏插入圖片描述

注意:最後一個if 判斷就是,如果當前隊列只有一個元素,我們刪除最後一個元素後需要將rear指針指向頭節點。

7.輸出序列

輸入和輸出連續的情況下

  • 輸入序列:1,2,3…n
  • 輸出序列:n…3,2,1

隊列

  • 輸入序列:1,2,3…n
  • 輸出序列:1,2,3…n

對於隊列無論輸入序列是否連續,輸出序列一定是一樣的,都是輸入順序。

棧 輸入和輸出非連續的情況下

  • 輸入序列:1,2,3
  • 輸出序列:3 2 1 、2 1 3 、2 3 1 、1 2 3 、1 3 2

輸出序列總共是上面五種加3 1 2 六種(按照排列組合),其中3 1 2不合法,按照這種輸出序列則入棧爲一次性將1 2 3全部入棧,此時出棧序列必爲3 2 1.

例子:
在這裏插入圖片描述
其中橙色標識出的序列都是不合法的,我們發現:出棧序列中每一個元素後面所有比它小的元素組成一個遞減序列,這樣的序列纔是合法的序列
比如:3142 這個不和法的序列,3後面比他小的1、2組成了遞增序列。

合法出 棧 序列的個數

進棧序列:1,2,3…n

f(n)=C(2n,n)/(n+1) 求算合法出棧序列的個數公式

8.隊列雙端序列

雙端隊列 允許兩端都可以進行入隊以及出隊操作的隊列

在這裏插入圖片描述

無論哪一端先出的元素在前,後出的元素在序列後。

如果我們把某一端的插入與刪除操作屏蔽,就構成了一個棧。

在這裏插入圖片描述

如果我們把一端的刪除屏蔽,一端的插入屏蔽,就構成了一個隊列。

在這裏插入圖片描述

8.受限的雙端隊列

輸出受限的雙端隊列

在這裏插入圖片描述

輸入受限的雙端隊列

在這裏插入圖片描述

下面我們找受限的雙端隊列的輸出序列

輸入序列:1,2,3,4

輸出受限的雙端隊列
在這裏插入圖片描述
對於上面的受限的雙端隊列,棧的判斷輸出序列完全適用,其中不合法序列有:

在這裏插入圖片描述
如果隊列改成下面的樣式我們測試上面的不合法序列可以得到,42314132不是合法的序列。
在這裏插入圖片描述

輸入受限的雙端隊列

在這裏插入圖片描述
對於上面的受限的雙端隊列,棧的判斷輸出序列完全適用,其中不合法序列有:

在這裏插入圖片描述

如果隊列改成下面的樣式我們測試上面的不合法序列可以得到,42134231不是合法的序列。

在這裏插入圖片描述

歡迎關注公衆號 理木客更多精彩等你發現

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章