C語言數據結構基礎學習筆記——棧和隊列

以前咱們學過了普通的線性表,接下來咱們來了解一下兩種特殊的線性表——棧和隊列。編程

棧是隻容許在一端進行插入或刪除的線性表。數組

棧的順序存儲結構也叫做順序棧,對於棧頂指針top,當棧爲空棧時,top=-1;當棧爲滿棧時,top=MaxSize-1。順序棧的定義爲:數據結構

#define MaxSize 50                            //定義棧中元素的最大個數  typedef struct{ Elemtype data[MaxSize]; //存放棧中元素 
    int top;                                  //棧頂指針 
}SqStack;                                     //順序棧的簡寫

順序棧的入棧操做爲:函數

bool Push(SqStack &S,ElemType x){ if(S.top==MaxSize-1) return false; S.data[++S.top]=x; return true; } 

順序棧的出棧操做爲:spa

bool Pop(SqStack &S,ElemType &x){ if(S.top==-1) return false; x=S.data[S.top--];       return true; } 

順序棧讀取棧頂元素爲:指針

bool GetTop(SqStack S,ElemType &x){ if(S.top==-1) return false; x=S.data[S.top]; return true; } 

順序棧讀取棧頂元素與出棧操做對比,注意讀取棧頂元素時棧頂指針沒有自減。code

對於一個數組,若是隻從數組頭部開始入棧,並無達到很高的空間利用率,所以咱們引入共享棧的概念。共享棧是兩個棧共用同一個數組,分別從數組頭部和數組尾部開始開始入棧。其定義爲:blog

#define MaxSize 100                            //定義棧中元素的最大個數  typedef struct{ Elemtype data[MaxSize]; //存放棧中元素 
    int top1;                                  //棧1頂指針 
    int top2;                                  //棧2頂指針 
}SqDoubleStack;                                //共享棧的簡寫
bool Push(SqStack &S,ElemType x,int stackNum){ if(S.top1+1==S.top2) return false; if(stackNum==1) S.data[++S.top1]=x; else if(stackNum==2) S.data[--S.top2]=x; return true; } 

共享棧的滿棧條件是top1+1=top2。遞歸

同時,棧也有鏈式存儲結構,叫做鏈棧,它空棧時top=NULL,通常不會滿棧。鏈棧的定義爲:隊列

typedef struct SNode{ ElemType data; //數據域
    struct SNode *next;                //指針域 
}SNode,*SLink;                         //鏈式棧的結點
typedef struct LinkStack{ SLink top; //棧頂指針 
    int count;                         //鏈式棧結點數 
}LinkStack;

棧有着豐富的應用場景,比較經典的題目有括號的匹配以及後綴表達式的求值。

①括號的匹配:給你一串雜亂的大,中,小括號的序列,讓你判斷這裏的括號序列滿不知足數學計算的規律(括號套括號)。主要思路是將全部的左括號依次入棧,碰到右括號出棧匹配,如果不一樣種的括號返回false,如果同一種括號則繼續以上操做,直到空棧而且數組中的字符串遍歷完成,返回true。

②後綴表達式的計算:後綴表達式是計算機最喜歡的一種表達式方式,例如(5+10+1*13)/14這個中綴表達式,它的後綴表達式爲5 10 + 1 13 * + 14 /,其將每一步計算的運算符號置後。利用棧計算後綴表達式的主要思路是:①將數字5入棧,再將數字10入棧;②當指針碰到運算符+時,將棧中的前兩個元素出棧進行計算(後出棧的數在前位),結果入棧,如本例值15入棧;③同上一步,計算1*13得13入棧,此時棧底值15,棧頂值13;④同上一步,指針碰到運算符+,將15與13求和,得值28入棧;⑤再同上一步,計算28/14=2入棧;⑥此時字符串數組遍歷完畢,棧中的惟一值2則爲表達式的結果。

棧思想的最重要的一個應用即是遞歸,遞歸是指在一個函數、過程或數據結構中的定義中又應用了它自身的編程思想。理解遞歸的一個基礎方法即是找到遞歸式和遞歸邊界,咱們來看兩個例子:

①用遞歸求n的階乘:

int F(int n){ if(n==0) return 1;                //遞歸邊界 
    else return n*F(n-1);             //遞歸式 
}

②求斐波那契數列的第n項:

int Fib(int n){ if(n==0) return 0;                 //遞歸邊界
    else if(n==1) return 1;            //遞歸邊界
    else return Fib(n-1)+Fib(n-2);     //遞歸式 
}

遞歸式是每一次遞歸過程的計算核心,而遞歸邊界就是每一次遞歸的結束標誌。

另外一種特殊的線性表是隊列,隊列的定義是隻容許在一端進行插入,而在另外一端進行刪除的線性表。

隊列的順序存儲結構是順序隊列,其定義爲:

#define MaxSize 50                             //定義隊列中元素的最大個數  typedef struct{ Elemtype data[MaxSize]; //存放隊列中元素 
    int front,rear;                            //隊頭指針和隊尾指針 
}SqQueue;

但對於一個數組隊列來講,每一次入隊和出隊都會浪費一個數組位置,因而咱們引入循環隊列的概念,隊尾指針rear在指到隊尾後會回到下標爲0的位置(利用取餘來實現),即每一次rear和front的更新基於如下操做:rear=(rear+1)%MaxSize,front=(front+1)%MaxSize。

可是這樣又產生了新的問題,rear=front究竟是隊空仍是隊滿沒法判斷。這樣的問題有如下兩種解決辦法:①設一個frag,做爲標誌位,當隊滿時frag=1;②犧牲一個數組位置,保留一個空餘單元,此時隊滿的判斷標準變成了(rear+1)%MaxSize=front,隊列中的元素數計算方法爲:(rear-front+MaxSize)%MaxSize。

循環隊列的入隊操做爲:

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; } 

隊列鏈式存儲的定義爲:

typedef struct{ ElemType data; //數據域
    struct LinkNode *next;            //指針域 
}LinkNode;                            //鏈式隊列的結點
typedef struct{ LinkNode *front,*rear;            //隊頭和隊尾指針 
}LinkQueue;

鏈式隊列的入隊和出隊相似於鏈表的相應操做。

相關文章
相關標籤/搜索