《大話數(shù)據(jù)結(jié)構(gòu)》學(xué)習(xí)筆記三

第4章 棧與隊列

棧是限定僅在表尾進(jìn)行插入和刪除操作的線性表。
隊列是只允許在一端進(jìn)行插入操作、而在另一端進(jìn)行刪除操作的線性表。

棧的定義

棧(stack)是限定僅在表尾進(jìn)行插入和刪除操作的線性表邪媳。

我們把允許插入和刪除的一端稱為棧頂(top),另一端稱為棧底(bottom)叽唱,不含任何數(shù)據(jù)元素的棧稱為空棧。棧又稱為后進(jìn)先出(Last In First Out)的線性表微宝,簡稱 LIFO 結(jié)構(gòu)棺亭。

棧的插入操作,叫做進(jìn)棧蟋软,也稱壓棧镶摘、入棧嗽桩。
棧的刪除操作,叫做出棧凄敢,也有的叫彈棧碌冶。

進(jìn)棧出棧的變化形式

元素數(shù)量多個,出棧次序會有很多種可能涝缝。

棧的抽象數(shù)據(jù)類型

ADT 棧
Data
  同線性表扑庞。元素具有相同的類型,相鄰元素具有前驅(qū)和后繼關(guān)系拒逮。
Operation
  InitStack(*S):初始化操作罐氨,建立一個空棧S。
  DestroyStack(*S):若棧存在滩援,則銷毀它栅隐。
  ClearStack(*S):將棧清空。
  StackEmpty(S):若棧為空狠怨,返回 true 约啊,否則返回 false邑遏。
  GetTop(S,*e):若棧存在且非空佣赖,用e返回S的棧頂元素。
  Push(*S,e):若棧S存在记盒,插入新元素e到棧S中并成為棧頂元素憎蛤。
  Pop(*S,e):刪除棧S中的棧頂元素,并用e返回其值纪吮。
  StackLength(S):返回棧S的元素個數(shù)俩檬。
endADT

棧的順序存儲結(jié)構(gòu)及實(shí)現(xiàn)

棧的順序存儲結(jié)構(gòu)

棧的結(jié)構(gòu)定義

typedef init SElemType;
typedef struct
{
  SElemType data[MAXSIZE]
  int top;     /* 用于棧頂指針 */
}SqStack;

棧的順序存儲結(jié)構(gòu)——進(jìn)棧操作

進(jìn)棧操作 push,其代碼如下:

Status Push (SqStack *S, SElemType e)
{
  if (S->top == MAXSIZE - 1) /* 棧滿 */
  {
    return ERROR;
  }
  S->top++;   /* 棧頂指針增加一 */
  S->data[S->top]=e;   /* 將新插入元素賦值給棧頂空間 */
  return OK;
}

棧的順序存儲結(jié)構(gòu)——出棧操作

出棧操作 pop碾盟,其代碼如下:

Status Pop (SqStack *S, SElemType *e)
{
  if(S->top==-1)
    return ERROR;
  *e=S->data[S->top]; /* 將要刪除的棧頂元素賦值給e */
  S->top--;   /* 棧頂指針減一 */
  return OK;
}

進(jìn)棧和出棧沒有涉及到任何循環(huán)語句棚辽,因此時間復(fù)雜度均是 O(1)。

兩棧共享空間

使用這樣的數(shù)據(jù)結(jié)構(gòu)冰肴,通常都是當(dāng)兩個棧的空間需求有相反關(guān)系時屈藐,也就是一個棧增長時另一個棧在縮短的情況。

棧的鏈?zhǔn)酱鎯Y(jié)構(gòu)及實(shí)現(xiàn)

棧的鏈?zhǔn)酱鎯Y(jié)構(gòu)

棧的鏈?zhǔn)酱鎯Y(jié)構(gòu)熙尉,簡稱為鏈棧联逻。
鏈棧的結(jié)構(gòu)代碼如下:

typedef struct StackNode
{
  SElemType data;
  struct StackNode *next;
}StackNode, *LinkStackPtr;

typedef struct LinkStack
{
  LinkStackPtr top;
  int count;
}

棧的鏈?zhǔn)酱鎯Y(jié)構(gòu)——進(jìn)棧操作

/* 插入元素 e 為新的棧頂元素 */
Status Push (LinkStack *S, SElemType e)
{
  LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode));
  s->data = e;
  s->next = s->top;  /* 把當(dāng)前的棧頂元素賦值給新結(jié)點(diǎn)的直接后繼 */
  S->top = s;  /* 將新的結(jié)點(diǎn)s賦值給棧頂指針 */
  S->count++;
  return OK;
}

棧的鏈?zhǔn)酱鎯Y(jié)構(gòu)——出棧操作

假設(shè)變量 p 用來存儲要刪除的棧頂結(jié)點(diǎn),將棧頂指針下移一位检痰,最后釋放 p 即可包归。

Status Pop (LinkStack *S, SElemType *e)
{
  LinkStackPtr p;
  if (StackEmpty(*S))
    return ERROR;
  *e = S->top->data;
  p=S->top;  /* 將棧頂結(jié)點(diǎn)賦值給p */
  S->top=S->top->next;  /* 使得棧頂指針下移一位,指向后一結(jié)點(diǎn) */
  free(p);  /* 釋放結(jié)點(diǎn) p */
  S->count--;
  return OK;
}

鏈棧的進(jìn)棧 push 和出棧 pop 操作沒有任何循環(huán)操作铅歼,時間復(fù)雜度均為O(1)公壤。
如果棧的使用過程中元素變化不可預(yù)料换可,有時很小,有時非常大厦幅,那么最好是用鏈棧锦担,反之,如果它的變化在可控范圍內(nèi)慨削,建議使用順序棧會更好一些洞渔。

棧的作用

棧的引入簡化了程序設(shè)計的問題,劃分了不同關(guān)注層次缚态,使得思考范圍縮小磁椒,更加聚焦于我們要解決的問題核心。

棧的應(yīng)用——遞歸

斐波那切數(shù)列實(shí)現(xiàn)

int Fbi (int i)
{
  if (i < 2)
    return i == 0 ? 0 : 1;
  return Fbi(i-1) + Fbi(i-2);
}
int main()
{
  int i;
  for (int i = 0;i < 40; i++)
    printf("%d ", Fbi(i));
  return 0;
}

遞歸定義

在高級語言中玫芦,調(diào)用自己和其他函數(shù)并沒有本質(zhì)的不同浆熔。我們把一個直接調(diào)用自己或通過一系列的調(diào)用語句間接地調(diào)用自己的函數(shù),稱做遞歸函數(shù)桥帆。
每個遞歸定義必須至少有一個條件医增,滿足遞歸不再進(jìn)行,即不再引用自身而是返回值退出老虫。

棧的應(yīng)用——四則運(yùn)算表達(dá)式求值

  1. 將中綴表達(dá)式轉(zhuǎn)化為后綴表達(dá)式(棧用來進(jìn)出運(yùn)算的符號)叶骨。

  2. 將后綴表達(dá)式進(jìn)行運(yùn)算得出結(jié)果(棧用來進(jìn)出運(yùn)算的數(shù)字)。

隊列的定義

隊列(queue)是只允許在一端進(jìn)行插入操作祈匙,而在另一端進(jìn)行刪除操作的線性表忽刽。

隊列是一種先進(jìn)先出(First In First Out)的線性表,簡稱FIFO夺欲。允許插入的一端稱為隊尾跪帝,允許刪除的一端稱為隊頭。

隊列的抽象數(shù)據(jù)類型

ADT 隊列(Queue)

Data
  同線性表些阅。元素具有相同的類型伞剑,相鄰元素具有前綴和后繼關(guān)系。
Operation
  InitQueue(*Q):初始化操作市埋,建立一個空隊列Q黎泣。
  DestroyQueue(*Q):若隊列Q存在,則銷毀它腰素。
  ClearQueue(*Q):將隊列Q清空聘裁。
  QueueEmpty(*Q):若隊列Q為空,返回 true弓千,否則返回 false衡便。
  GetHead(Q,*e):若隊列Q存在且非空,用e返回隊列Q的隊頭元素。
  EnQueue(*Q,e):若隊列Q存在镣陕,插入新元素e到隊列Q中并成為隊尾元素谴餐。
  DeQueue(*Q,*e):刪除隊列Q中隊頭元素,并用e返回其值呆抑。
  QueueLength(Q):返回隊列Q的元素個數(shù)岂嗓。
endADT

循環(huán)隊列

循環(huán)隊列定義

我們把隊列的這種頭尾相接的順序存儲結(jié)構(gòu)稱為循環(huán)隊列。

隊列的鏈?zhǔn)酱鎯Y(jié)構(gòu)及實(shí)現(xiàn)

隊列的鏈?zhǔn)酱鎯Y(jié)構(gòu)鹊碍,其實(shí)就是線性表的單鏈表厌殉,只不過它只能尾進(jìn)頭出而已,我們把它簡稱為鏈隊列侈咕。
鏈隊列的結(jié)構(gòu)為:

typedef int QElemType;

typedef struct QNode  /* 節(jié)點(diǎn)結(jié)構(gòu) */
{
  QElemType data;
  struct QNode *next;
}QNode,*QueuePtr;

typedef struct  /* 隊列的鏈表結(jié)構(gòu) */
{
  QueuePtr front,rear; /* 隊頭公罕、隊尾指針 */
}LinkQueue;

隊列的鏈?zhǔn)酱鎯Y(jié)構(gòu)——入隊操作

Status EnQueue(LinkQueue *Q, QElemType e)
{
  QueuePtr s = (QueuePtr)malloc(sizeof(QNode));
  if(!s)  /* 存儲分配失敗 */
    exit(OVERFLOW);
  s->data = e;
  s->next = NULL;
  Q->rear->next = s;  /* 把擁有元素e新結(jié)點(diǎn)s賦值給原隊尾節(jié)點(diǎn)的后繼 */
  Q->rear = s;  /* 把當(dāng)前的s設(shè)置為隊尾結(jié)點(diǎn),rear指向s */
  return OK;
}

隊列的鏈?zhǔn)酱鎯Y(jié)構(gòu)——出隊操作

Status DeQueue(LinkQueue *Q, QElemType *e)
{
  QueuePtr p;
  if(Q->front==Q->rear)
    return ERROR;
  p=Q->front->next;  /* 將欲刪除的隊頭結(jié)點(diǎn)暫存給p */
  *e=p->data;  /* 將欲刪除的隊頭結(jié)點(diǎn)的值賦值給e */
  Q->front->next=p->next;  /* 將原隊頭結(jié)點(diǎn)后繼p->next賦值給頭結(jié)點(diǎn)后綴 */
  if(Q->rear==p)  /* 若隊頭是隊尾耀销,則刪除后將rear指向頭結(jié)點(diǎn) */
    Q->rear=Q->front;
  free(p);
  return OK;
}

在可以確定隊列長度最大值的情況下楼眷,建議用循環(huán)隊列,如果你無法預(yù)估隊列的長度時熊尉,則用鏈隊列罐柳。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市狰住,隨后出現(xiàn)的幾起案子张吉,更是在濱河造成了極大的恐慌,老刑警劉巖转晰,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芦拿,死亡現(xiàn)場離奇詭異,居然都是意外死亡查邢,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門酵幕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來扰藕,“玉大人,你說我怎么就攤上這事芳撒〉松睿” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵笔刹,是天一觀的道長芥备。 經(jīng)常有香客問我,道長舌菜,這世上最難降的妖魔是什么萌壳? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上袱瓮,老公的妹妹穿的比我還像新娘缤骨。我一直安慰自己,他們只是感情好尺借,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布绊起。 她就那樣靜靜地躺著,像睡著了一般燎斩。 火紅的嫁衣襯著肌膚如雪虱歪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天栅表,我揣著相機(jī)與錄音实蔽,去河邊找鬼。 笑死谨读,一個胖子當(dāng)著我的面吹牛局装,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播劳殖,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼铐尚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了哆姻?” 一聲冷哼從身側(cè)響起宣增,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎矛缨,沒想到半個月后爹脾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡箕昭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年灵妨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片落竹。...
    茶點(diǎn)故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡泌霍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出述召,到底是詐尸還是另有隱情朱转,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布积暖,位于F島的核電站藤为,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏夺刑。R本人自食惡果不足惜缅疟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一分别、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧窿吩,春花似錦茎杂、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至轧邪,卻和暖如春刽脖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背忌愚。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工曲管, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人硕糊。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓院水,卻偏偏與公主長得像,于是被迫代替她去往敵國和親简十。 傳聞我的和親對象是個殘疾皇子檬某,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容