大話西遊之王道考研數據結構第四講---隊列

                                                  第四講---隊列

一、隊列

隊列簡稱隊,一種操作受限的線性表。只允許在一端(隊尾)插入,一端(隊頭)刪除(出去)。也就是先進先出的線性表。空隊列是指不含任何元素的空表。

舉個栗子

上次我們講到唐僧師徒五人春遊時候掉進了一口井裏,費了老大的勁幾個人纔出來。此時,唐僧以及半殘了。他們幾個準備找個村莊,讓師傅休息一下。他們就一路上沿着一條小溪走,林盡水源,便得一山,山有小口,彷彿若有光..初極狹,才通人。(他們看到了一個洞洞)。心想洞洞後面一定有人家,於是乎...這幫人又開始鑽洞了:

1.初極狹,才通人~不存在在洞裏面,後面那個人把前面那個人超了,或者是並排走的情況。

2.八戒要想出去,必須唐僧先出去,然後猴哥出去,八戒才能出去。

(先進先出)

二、循環隊列

傳統隊列的存儲方式一般會造成很大的空間浪費,比如我們申請了50個空間,剛開始時候隊頭是0,隊尾也是0,現在我們加入了40個人,隊頭是0,隊尾是39。現在讓着40個人全部出去,隊頭是39,隊尾是39。因爲加人是從隊尾加的,隊尾最大是49,所以只能在加10個人了。前面0~39這40個元素空間就全部浪費了。所以傳統的隊列一般是完全用不了的。

所以我們採用循環隊列,使得隊伍真的能達到其預先申請的最大人數。循環隊列完全可以理解爲一個鐘錶的形式。在最開始時候:

 我們把整個表分成8個小格,理論上,我們最大可以存儲8個個體,但是我們一般存7個(後面會講到爲什麼)。

front爲隊頭,指向排在第一個的人;rear爲隊尾,指向排在最後一個人的下一位(這是規定,這樣的話後面一些操作會很方便)。

剛開始時候,隊列的頭front和尾rear都指向第0個格子,表示隊裏還沒有人。

現在唐僧加進來以後,整個循環隊列成了這個樣子:

 

所有人都加進來以後:

我們可以再加幾個人,方便說明隊滿時候的狀態:

假設我們一共加了8個人,這個時候,可以看到rear和front又同時指向了0號位置,這個狀態和我們之前隊空時候是一摸一樣的。那麼如何去檢測隊列是否滿了呢?你可以另外開闢一個變量,記錄當前隊列人數,通過檢測這個變量是否和最大人數相等,來檢測隊列是否滿了。但是我們一般不另外開闢,我們會用一個比較騷的操作去解決這個問題(身爲一個程序員,騷是第一位)。我們一般讓最大人數是MaxSize-1,這裏就是7,這樣的話:

我們只需要判斷(rear+1)%MaxSize == front就好了,而且只有隊滿時候,返回值纔會是true。

我這裏就只講判斷是否隊滿的操作,插入刪除時候指針變化可以看書上,講的很清楚,也比較簡單。和傳統隊列相比,無非就是增加了一個模運算。

三、循環隊列的順序存儲結構

1.老規矩,先說下結構體:

#define MaxSize 50 //最大棧的容量(井裏最多放50人)
typedef struct{
    int data[MaxSize];
    int front;//用來表示隊頭的位置
    int rear;//用來表示隊尾的位置
}SqQueue;//一直沒有說這個,Sq表示的是線性表的順序表示Sequence

2.InitQueue(&Q):初始化隊列

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

3.isEmpty(Q):判斷是否爲空

bool isEmpty(SqQueue Q){
    if(Q.rear == Q.front)//隊頭等於隊尾當然是隊裏面沒人了
        return true;
    else
        return false;
}

4.EnQueue(&Q,x):將x加入隊列中

bool EnQueue(SqQueue &Q, int x){
    //1.檢查
    if((Q.rear+1)%MaxSize == Q.front)//循環隊列判斷是否隊滿
        return false;
    //2.賦值
    Q.data[Q.rear] = x;
    //3.修改
    Q.rear = (Q.rear+1)%MaxSize; //循環隊列下遞增的方式
    //4.返回成功
    return true;
    
}

5.DeQueue(&Q,&x):將隊首元素出隊並賦值給x

bool DeQueue(SqQueue &Q,int x){
    //1.檢查
    if(Q.rear==Q.front){
        return false;
    }
    //2.賦值
    x = Q.data[Q.front];
    //3.修改
    Q.front = (Q.front+1)%MaxSize;
    return true;
}

6.isFull(Q)檢查是否隊滿:

bool isFull(SqQueue Q){
    if((Q.rear+1)%MaxSize==Q.front){
        return true;
    }
    else{
        return false;
    }
}

7.getSum(Q)

int getSum(SqQueue Q){
    //這裏面有個騷操作 + MaxSize
    //這樣可以保證%前面那一項始終爲正
    //因爲我們有可能遇到Q.rear = 1,Q.front= 6的情況
    //而 (a+b)%b == a%b
    //這是取模運算裏面的一個定理
    return (Q.rear - Q.front + MaxSize)%MaxSize;
    
}

四、鏈式隊列和雙端隊列

和鏈式棧一樣,鏈式隊列也不是考試的主要內容。所以不需要太多的瞭解,核心內容是頭指針(front)指向隊頭結點,尾指針(rear)指向隊尾結點(沒有頭結點,除非特殊說明)。

 

我們主要看雙端隊列。在循環隊列中,只能在隊頭出隊,隊尾入隊。但是雙端隊列就不一樣了,其兩端都可以出隊。爲了更好理解,我們就把雙端隊列的兩端叫做前端和後端。雙端隊列一般細分爲兩種(兩端都可以進出的隊列一般不考,因爲太簡單了),一種是輸出受限(倆插一刪,輸出受限,意思就是把出隊的那一個操作限制了,出隊的操作是刪除嘛,所以少一個刪除),一種是輸入受限(倆刪一插)。

書上對雙端隊列裏面,前段進入的元素排列在隊列中後端進的元素的前面....xxxx..xx...x。反正我是記不住這些東西~雙端隊列一般考的是選擇題,隊列元素一般不超過5個,我們完全可以一個一個試,就可以得到答案了。現在直接做一個題把:

                                   

 

五、習題

 

 

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