數(shù)據(jù)結(jié)構(gòu)(棧和隊(duì)列)

是限定僅在表尾進(jìn)行插入和刪除操作的線性表。表尾端稱為棧頂屠尊,表頭端稱為棧底。不含元素的空表稱為空棧耕拷。
棧是后進(jìn)先出的線性表讼昆。

隊(duì)列是只允許在一端進(jìn)行插入操作、而在另一端進(jìn)行刪除操作的線性表骚烧。隊(duì)列是先進(jìn)先出的線性表浸赫。

1. 棧

(1) 順序棧的表示和實(shí)現(xiàn)

順序棧是指利用順序存儲結(jié)構(gòu)實(shí)現(xiàn)的棧,即利用一組地址連續(xù)的存儲單元依次存放自棧底到棧頂?shù)臄?shù)據(jù)元素赃绊,同時(shí)附設(shè)指針top指示棧頂元素在順序棧中的位置既峡。另設(shè)指針base指示棧底元素在順序棧中的位置。

當(dāng)top和base的值相等時(shí)碧查,表示空棧运敢。

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

#define MAXSIZE 100 /* 存儲空間初始分配量 */ 
typedef int Status;
 typedef int SElemType; /* SElemType類型根據(jù)實(shí)際情況而定,這里假設(shè)為int */ 
/* 順序棧結(jié)構(gòu) */
typedef struct{        
    SElemType *base;//棧底指針
    SElemType *top;//棧頂指針
    int stacksize;//椫沂郏可用的最大容量
}

base指針的值為NULL传惠,則表明棧結(jié)構(gòu)不存在。
棧非空時(shí)稻扬,top始終指向棧頂元素的上一個(gè)位置卦方。

2. 順序棧的初始化

  • 為順序棧動態(tài)分配一個(gè)最大容量為MAXSIZE的數(shù)組空間,使base指向這段空間的基地址泰佳,即棧底盼砍。
  • 棧頂指針top初始值為base尘吗。
  • stacksize置為棧的最大容量MAXSIZE。

Status InitStack(SqStack &S)
{
    S.base = new SElemType[MAXSIZE]; //為順序棧動態(tài)分配一個(gè)最大容量為MAXSIZE的數(shù)組空間
    if(!S.base) exit(OVERFLOW);//存儲分配失敗
    S.top = S.base;//top初始為base浇坐,空棧
    S.stacksize = MAXSIZE;// stacksize置為棧的最大容量MAXSIZE
    return OK;
}

3. 順序棧的入棧

  • 判斷棧是否為滿摇予,若滿則返回ERROR。
  • 將新的元素壓入棧頂吗跋,棧頂指針加1。

Status Push(SqStack &S,SElemType e)
{
    //  插入元素e為新的棧頂元素
    if(S.top - S.base == S.stacksize) return ERROR;//棧滿
    *S.top ++ = e; //元素e壓入棧頂宁昭,棧頂指針加1
    return OK;
}

4.出棧

  • 判斷棧是否為空跌宛,若空則返回ERROR。
  • 棧頂指針減1积仗,棧頂元素出棧疆拘。

Status Pop(SqStack &S,SElemType &e)
{
    //刪除S的棧頂元素,用e 返回其值
    if(S.top == S.base) return ERROR ; // 椉挪埽空
    e = *--S.top; //棧頂指針減1哎迄,將棧頂元素賦值給e
    return OK;
}

5. 取棧頂元素

當(dāng)棧非空時(shí),此操作返回當(dāng)前棧頂元素的值隆圆,棧頂保持不變漱挚。

Status GetTop(SqStack S)
{
    if (S.top ! = S.base)  //棧非空
        return *(S.top -1);//返回棧頂元素的值,棧頂指針不變渺氧。
    
}

(2) 鏈棧的表示和實(shí)現(xiàn)

鏈棧是指采用鏈?zhǔn)酱鎯Y(jié)構(gòu)實(shí)現(xiàn)的棧旨涝。


1. 鏈棧的存儲結(jié)構(gòu)


typedef struct StackNode
{
        SElemType data;
        struct StackNode *next;

}StackNode,*LinkStackPtr;

2. 鏈棧的初始化

鏈棧的初始化操作就是構(gòu)造一個(gè)空棧,因?yàn)闆]必要設(shè)頭結(jié)點(diǎn)侣背,所以直接將棧頂指針置空即可白华。

Status InitStack(LinkStack &S)
{//構(gòu)建一個(gè)空棧S,棧頂指針置空
    S = NULL:
    return OK;
}

3. 鏈棧的入棧

  • 為棧元素e分配空間贩耐,用指針p指向弧腥。
  • 將新結(jié)點(diǎn)數(shù)據(jù)域置為e。
  • 將新結(jié)點(diǎn)插入棧頂
  • 修改棧頂指針為p潮太。
Status Push(LinkStack &S,SElemType e)
{
    p = new StackNode; //生成新結(jié)點(diǎn)
    p->data  = e;//將新結(jié)點(diǎn)數(shù)據(jù)域置為e
    p->next = S;//將新結(jié)點(diǎn)插入棧頂
    S = p;//修改棧頂指針為p
    return OK;
}

4. 鏈棧的出棧

  • 判斷棧是否為空管搪,若空則返回ERROR。
  • 將棧頂元素賦值給e消别。
  • 臨時(shí)保存棧頂元素的空間抛蚤,以備釋放。
  • 修改棧頂指針寻狂,指向新的棧頂元素岁经。
  • 釋放元棧頂元素

Status Pop(LinkStack &S,SElemType &e)
{
      //刪除S的棧頂元素,用e返回其值蛇券。
      if(S==NULL) return ERROR;
      e = S -> data;
      p = S;
      S = S->next;
      delete p;
      return OK;
 }

5. 取棧頂元素

SElemType GetTop (LinkStack S)
{
    if(S != NULL) //棧非空
        return S->data;//返回棧頂元素缀壤,棧指針不變樊拓。
}

(3) 棧與遞歸

Hanoi塔問題

  1. 每次只能移動一個(gè)圓盤。
    2.圓盤可以插在A塘慕、B和C中的任一塔座上筋夏。
  2. 任何時(shí)刻都不能將一個(gè)較大的圓盤壓在較小的圓盤之上。


Hanoi塔問題的遞歸算法

  • 如果 n=1,則直接將編號為1的圓盤從A移到C图呢,遞歸結(jié)束条篷。
  • 否則:

1.遞歸,將A上編號為1至n-1的圓盤移到B蛤织,C做輔助塔赴叹。

  1. 直接將編號為n的圓盤從A移到C。
  2. 遞歸指蚜,將B上編號為1至n-1的圓盤移動到C乞巧,A做輔助塔。
void Hanoi(int n,char A,,char B,char C)
{
    if (n == 1) move(A,1,C); //將編號為1的圓盤從A移到C
    else
    {
          Hanoi(n-1,A,C,B); //將A上編號為1至n-1的圓盤移到B摊鸡,C做輔助
          move(A,n,C);//將編號為 n的圓盤從A移到C
          Hanoi(n-1,B,A,C);//將B上編號為1至n-1的圓盤移到C绽媒,A做輔助
    }
}

/* 將搬動操作定義為move(A,n,C),是指將編號為n的圓盤從A移動到C免猾,同時(shí)設(shè)置一個(gè)初始值為0的全局變量m,對搬動進(jìn)行計(jì)數(shù)是辕。*/
int m;
void move(char A,int n,char C)
{
    count<<++m<<","<<n<<","<<A<<","<<C<<endl;
}

2. 隊(duì)列

(1) 循環(huán)隊(duì)列-隊(duì)列的順序表示和實(shí)現(xiàn)

1. 隊(duì)列的順序存儲結(jié)構(gòu)

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存儲空間初始分配量 */
 typedef int Status;
 typedef int QElemType; /* QElemType類型根據(jù)實(shí)際情況而定,這里假設(shè)為int */
 /* 循環(huán)隊(duì)列的順序存儲結(jié)構(gòu) */
typedef struct{    
    QElemType *base /*存儲空間的基地址*/
    int front;        /* 頭指針 */
    int rear;        /* 尾指針掸刊,若隊(duì)列不空免糕,指向隊(duì)列尾元素的下一個(gè)位置 */

  1. 附設(shè)兩個(gè)整型變量front和rear指針分別指示隊(duì)列頭元素及隊(duì)列尾元素的位置。
  2. 初始化創(chuàng)建空隊(duì)列時(shí)忧侧,令front = rear = 0
  3. 每當(dāng)插入新的隊(duì)列尾元素時(shí)石窑,尾指針rear增1,每當(dāng)刪除隊(duì)列頭元素時(shí)蚓炬,頭指針front增1.
  4. 在非空棧中松逊,頭指針始終指向隊(duì)列頭元素,而尾指針始終指向隊(duì)列尾元素的下一個(gè)位置肯夏。

循環(huán)隊(duì)列经宏,解決假溢出問題

隊(duì)空隊(duì)滿的判斷:

  1. 少用一個(gè)元素空間。即隊(duì)列空間大小為m時(shí)驯击,由m-1個(gè)元素就認(rèn)為是隊(duì)滿烁兰。
  2. 當(dāng)頭、尾指針相等時(shí)徊都,隊(duì)空沪斟。當(dāng)尾指針在循環(huán)意義上加1后是等于頭指針,則認(rèn)為隊(duì)滿暇矫。
    隊(duì)空條件:Q.front == Q.rear
    隊(duì)滿條件:(Q.rear+1)%MAXQSIZE == Q.front

2. 循環(huán)隊(duì)列的初始化

  • 為隊(duì)列分配一個(gè)最大容量的MAXSIZE的數(shù)組空間主之,base指向數(shù)組空間的首地址择吊。
  • 頭指針和尾指針為零,表示隊(duì)列為空槽奕。

/* 初始化一個(gè)空隊(duì)列Q */
Status InitQueue(SqQueue *Q)
{
        Q.base = new QElemType[MAXQSIZE]; //為隊(duì)列分配一個(gè)最大容量為MAXQSIZE的數(shù)組空間
        if (!Q.base) exit(OVERFLOW);
        Q->front =Q->rear=0;
        return  OK;
}

3. 求循環(huán)隊(duì)列的長度

/* 返回Q的元素個(gè)數(shù)几睛,也就是隊(duì)列的當(dāng)前長度 */
int QueueLength(SqQueue Q)
{
    return  (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}

4. 循環(huán)隊(duì)列的入隊(duì)
  • 判斷隊(duì)列是否滿,若滿則返回ERROR粤攒。
  • 將新元素插入隊(duì)尾所森。
  • 隊(duì)尾指針加1。
Status EnQueue(SqQueue &Q,QElemType e){ 
    if ((Q.rear+1)%MAXSIZE == Q.front)  /* 隊(duì)列滿的判斷 */        
        return ERROR;   
    Q.base[Q.rear]=e;           /* 將元素e賦值給隊(duì)尾 */ 
    Q->rear=(Q.rear+1)%MAXSIZE;/* rear指針向后移一位置夯接, */                                  
    return  OK;
}

5. 循環(huán)隊(duì)列的出隊(duì)

  • 判斷隊(duì)列是否為空必峰,若為空則返回ERROR。
  • 保存隊(duì)列頭元素钻蹬。
  • 對頭指針加1。
Status DeQueue(SqQueue &Q,QElemType &e){    
    if (Q.front == Q.rear)          /* 隊(duì)列空的判斷 */            
        return ERROR;   
    e=Q.base[Q.front];              /* 將隊(duì)頭元素賦值給e */
    Q.front=(Q.front+1)%MAXSIZE;    /* front指針向后移一位置凭需,若到最后則轉(zhuǎn)到數(shù)組頭部 */ 
    return  OK;
}

6. 取循環(huán)隊(duì)列的對頭元素

SElemType GetHead(SqQueue Q)
{
    if(Q.front != Q.rear)//隊(duì)列非空
        return Q.base[Q.front];//返回隊(duì)頭元素的值问欠,隊(duì)頭指針不變。
}

(2) 鏈隊(duì)-隊(duì)列的鏈?zhǔn)奖硎竞蛯?shí)現(xiàn)

鏈隊(duì)采用鏈?zhǔn)酱鎯Y(jié)構(gòu)實(shí)現(xiàn)的隊(duì)列粒蜈。為了方便操作顺献,給鏈隊(duì)添加一個(gè)頭結(jié)點(diǎn),并令頭指針始終指向頭結(jié)點(diǎn)枯怖。


1. 隊(duì)列的鏈?zhǔn)酱鎯Y(jié)構(gòu)

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存儲空間初始分配量 */ 
typedef int Status;  
typedef int QElemType; /* QElemType類型根據(jù)實(shí)際情況而定注整,這里假設(shè)為int */ 
typedef struct QNode     /* 結(jié)點(diǎn)結(jié)構(gòu) */
{   
    QElemType data;   
    struct QNode *next;
}QNode,*QueuePtr; 
typedef struct          /* 隊(duì)列的鏈表結(jié)構(gòu) */
{   
    QueuePtr front,rear; /* 隊(duì)頭、隊(duì)尾指針 */
}LinkQueue;
 

2. 鏈隊(duì)的初始化

  • 生成一個(gè)新結(jié)點(diǎn)作為頭結(jié)點(diǎn)度硝,對頭和隊(duì)尾指針指向此結(jié)點(diǎn)肿轨。
  • 頭結(jié)點(diǎn)的指針域置空。
Status InitQueue(LinkQueue &Q)
{
    //構(gòu)造一個(gè)空隊(duì)
    Q.front = Q.rear = new QNode;
    Q.front->next = NULL;
    return OK;
}

3. 鏈隊(duì)的入隊(duì)

  • 為元素分配新的結(jié)點(diǎn)空間蕊程,用指針p指向椒袍。
  • 將新結(jié)點(diǎn)數(shù)據(jù)域設(shè)置為e。
  • 將新結(jié)點(diǎn)插入到隊(duì)尾藻茂。
  • 修改隊(duì)尾指針為p驹暑。
Status EnQueue(LinkQueue &Q,QElemType e)
{   
    p =  new QNode;
    p->data=e;  
    p->next=NULL;   
    Q.rear->next=p;
    Q.rear = p          
    return OK;
}

4. 鏈隊(duì)的出隊(duì)

  • 判斷隊(duì)列是否為空,若空則返回ERROR辨赐。
  • 臨時(shí)保存隊(duì)列的頭元素优俘,以備釋放空間。
  • 修改隊(duì)頭指針掀序,指向下一個(gè)結(jié)點(diǎn)帆焕。
  • 判斷出隊(duì)元素是否為最后一個(gè)元素,若是森枪,則將隊(duì)尾指針重新賦值视搏,指向隊(duì)頭結(jié)點(diǎn)审孽。
  • 釋放元隊(duì)頭元素空間。
Status DeQueue(LinkQueue &Q,QElemType &e)
{   
    QueuePtr p; 
    if(Q.front==Q.rear)     
        return ERROR;   
    p=Q.front->next;        //p指向隊(duì)頭元素   
    e=p->data;          //e保存隊(duì)頭元素的值     
    Q.front->next=p.next;   //修改頭指針
    if(Q.rear==p)   //最后一個(gè)元素被刪浑娜,隊(duì)尾指針指向隊(duì)頭指針   
        Q.rear=Q.front; 
    delete p;   
    return OK;
}
 

4. 取鏈隊(duì)的隊(duì)頭元素

SElemType GetHead(LinkQueue Q)
{
    if(Q.front != Q.rear) 
        return Q.front->next->data;
}

(3) 循環(huán)隊(duì)列和鏈隊(duì)列的比較

  1. 時(shí)間上佑力,基本操作都是常數(shù)時(shí)間,即O(1),不過筋遭,循環(huán)隊(duì)列是事先申請好空間打颤,使用期間不釋放,而對于鏈隊(duì)列漓滔,每次申請和釋放結(jié)點(diǎn)會存在一些時(shí)間開銷编饺,如果入隊(duì)出隊(duì)頻繁,則兩者還是略有差異响驴。
  2. 空間上透且,循環(huán)隊(duì)列必須有固定的長度,所以就有了存儲元素個(gè)數(shù)和空間浪費(fèi)的問題豁鲤。而鏈隊(duì)列不存在這樣的問題秽誊,盡管它需要一個(gè)指針域,會產(chǎn)生一些空間上的開銷琳骡,但也可以接受锅论。所以在空間上,鏈隊(duì)列更加靈活楣号。
  3. 總之最易,在可以確定隊(duì)列長度最大值的情況下,建議用循環(huán)隊(duì)列炫狱,如果無法預(yù)估隊(duì)列的長度藻懒,則用鏈隊(duì)列。

插入元素時(shí)間復(fù)雜度為O(1)视译,刪除時(shí)是O(n)束析,因?yàn)楹竺娴乃性匾蚯耙?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市憎亚,隨后出現(xiàn)的幾起案子员寇,更是在濱河造成了極大的恐慌,老刑警劉巖第美,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝶锋,死亡現(xiàn)場離奇詭異,居然都是意外死亡什往,警方通過查閱死者的電腦和手機(jī)扳缕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人躯舔,你說我怎么就攤上這事驴剔。” “怎么了粥庄?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵丧失,是天一觀的道長。 經(jīng)常有香客問我惜互,道長布讹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任训堆,我火速辦了婚禮描验,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘坑鱼。我一直安慰自己膘流,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布鲁沥。 她就那樣靜靜地躺著睡扬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪黍析。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天屎开,我揣著相機(jī)與錄音阐枣,去河邊找鬼。 笑死奄抽,一個(gè)胖子當(dāng)著我的面吹牛蔼两,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逞度,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼额划,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了档泽?” 一聲冷哼從身側(cè)響起俊戳,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎馆匿,沒想到半個(gè)月后抑胎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡渐北,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年阿逃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,727評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡恃锉,死狀恐怖搀菩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情破托,我是刑警寧澤肪跋,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站炼团,受9級特大地震影響澎嚣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瘟芝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一易桃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锌俱,春花似錦晤郑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吭练,卻和暖如春诫龙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鲫咽。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工签赃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人分尸。 一個(gè)月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓锦聊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親箩绍。 傳聞我的和親對象是個(gè)殘疾皇子孔庭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評論 2 354

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