1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        面試官問我什么是「棧」,我隨手畫了10張圖來解釋

        共 10825字,需瀏覽 22分鐘

         ·

        2021-09-17 18:25




        關(guān)注、星標公眾號,直達精彩內(nèi)容

        ID:技術(shù)讓夢想更偉大

        作者:李肖遙

        棧的概念

        棧(stack)是限定僅在表的一端進行操作的數(shù)據(jù)結(jié)構(gòu),且棧是一種先進后出的數(shù)據(jù)結(jié)構(gòu),允許操作的一端稱為棧頂,不允許操作的稱為棧底,如下圖所示:

        之前我們講到了鏈表,我們只能夠?qū)ζ滏湵淼谋砦步Y(jié)點進行操作,并且只能進行插入一個新的結(jié)點與刪除最末尾的這個結(jié)點兩個操作,而這樣強限制性的‘鏈表’,就是我們所說的。

        就像是一個死胡同一樣,只有一個出口,如圖所示,有個概念:

        棧的結(jié)點設(shè)計

        棧分為數(shù)組棧鏈表棧,其區(qū)別如下:

        • 數(shù)組棧使用數(shù)組進行功能的模擬,實現(xiàn)較為快速和便利;

        • 鏈表棧使用鏈表的思路去設(shè)計,實現(xiàn)相比較說較為麻煩,但是其穩(wěn)定,且不易出錯;

        在鏈表棧中又分為靜態(tài)鏈表棧和動態(tài)鏈表棧,其區(qū)別如下:

        • 靜態(tài)鏈表棧給定棧的空間大小,不允許超過存儲超過給定數(shù)據(jù)大小的元素;

        • 動態(tài)棧使用的是自動創(chuàng)建空間的方法進行創(chuàng)建,只要符合機器的硬件要求以及編譯器的控制,其理論上是極大的。

        數(shù)組棧

        其實際就是用一段連續(xù)的存儲空間來存儲棧中的數(shù)據(jù)元素,有以下特點:

        1. 元素所占的存儲空間必須連續(xù),這里的連續(xù)是指的邏輯連續(xù),而不是物理連續(xù)。

        2. 元素在存儲空間的位置是按邏輯順序存放的

        我們來舉例說明,鑒于C語言數(shù)組下標都是0開始,并且棧的使用需要的空間大小難以估計,所以初始化空棧的時候,不應(yīng)該設(shè)定棧的最大容量。

        我們先為棧設(shè)定一個基本容量,在應(yīng)用過STACK_程當中,當棧的空間不夠用時,再逐漸擴大。

        設(shè)定2個常量,STACK_INIT_SIZE(存儲空間初始化分配量)和STACK_INCREMENT(存儲空間分配增量),宏定義如下

        #define STACK_INIT_SIZE 1000 //數(shù)值可以根據(jù)實際情況確定
        #define STACK_INCREMENT 10   //數(shù)值可以根據(jù)實際情況確定

        棧的定義如下

        typedef struct      
        {
            void *base; 
            void *top;
            int stackSize;
        } SqSTACK;
        • base 表示棧底指針

        • top 表示棧頂指針

        • stackSize 表示棧當前可以使用的最大容量

        若base的值是NULL,表示棧結(jié)構(gòu)不存在;top初始值指向棧底,即top = base;

        每當插入新的元素時,指針top就增1,反之刪除就減1,非空棧中的棧頂指針始終在棧頂元素的下一個指針上面。

        數(shù)據(jù)元素和棧頂指針的關(guān)系如下圖所示:

        鏈表棧

        我們以鏈表棧的動態(tài)鏈表棧為例子,進行棧的設(shè)計。

        首先是棧的結(jié)點,設(shè)計出兩個結(jié)構(gòu)體,一個結(jié)構(gòu)體Node表示結(jié)點,其中包含有一個data域和next指針,如圖所示:

        Node

        其中data表示數(shù)據(jù),next指針表示下一個的指針,其指向下一個結(jié)點,通過next指針將各個結(jié)點鏈接。

        接下來是我們設(shè)計的重點,為這個進行限制性的設(shè)計,我們需要額外添加一個結(jié)構(gòu)體,其包括了一個永遠指向棧頭的指針top一個計數(shù)器count記錄元素個數(shù)。

        其主要功效就是設(shè)定允許操作元素的指針以及確定棧何時為空,如圖所示:

        Stack

        這里我采用的是top和count組合的方法。其代碼可以表示為:

        //棧的結(jié)點設(shè)計
        //單個結(jié)點設(shè)計,數(shù)據(jù)和下一個指針
        typedef struct node     
        {

            int data; 
            struct node *next;
        } Node;

        利用上面的結(jié)點創(chuàng)建棧,分為指向頭結(jié)點的top指針和計數(shù)用的count

        typedef struct stack    
        {
            Node *top;
            int count;
        } Link_Stack;

        棧的基本操作—入棧(壓棧)

        入棧的基本順序可以用以下圖所示:

        入棧(push)操作時,我們只需要找到top所指向的空間,創(chuàng)建一個新的結(jié)點,將新的結(jié)點的next指針指向top指針指向的空間,再將top指針轉(zhuǎn)移,并且指向新的結(jié)點,這就是是入棧操作。

        其代碼可以表示為:


        //入棧 push
        Link_Stack *Push_stack(Link_Stack *p, int elem)
        {
            if (p == NULL)
                return NULL;
            Node *temp;
            temp=(Node*)malloc(sizeof(Node));
            //temp = new Node;
            temp->data = elem;
            temp->next = p->top;
            p->top = temp;
            p->count++;
            return p;
        }

        棧的基本操作—出棧

        出棧(pop)操作,是在棧不為空的情況下,重復(fù)說一次,一定要進行判空操作,將棧頂?shù)脑貏h除,同時top指針,next向下進行移動即可的操作。

        其代碼可以表示為:

        //出棧 pop
        Link_Stack *Pop_stack(Link_Stack *p)
        {
            Node *temp;
            temp = p->top;
            if (p->top == NULL)
            {
                printf("錯誤:棧為空");
                return p;
            }
            else
            {
                p->top = p->top->next;
                free(temp);
                //delete temp;
                p->count--;
                return p;
            }
        }

        棧的基本操作—遍歷

        這個就很常見了,也是我們調(diào)試必須的手段。

        棧的遍歷相對而言比較復(fù)雜,由于棧的特殊性質(zhì),其只允許在一端進行操作,所以遍歷操作操作永遠都是逆序的

        簡單一點描述,其過程為,在棧不為空的情況下,一次從棧頂元素向下訪問,直到指針指向空(即到棧尾)為結(jié)束。

        其代碼可以表示為:

        //遍歷棧:輸出棧中所有元素
        int show_stack(Link_Stack *p)
        {
            Node *temp;
            temp = p->top;
            if (p->top == NULL)
            {
                printf("");
                printf("錯誤:棧為空");
                return 0;
            }
            while (temp != NULL)
            {
                printf("%d\t", temp->data);
                temp = temp->next;
            }
            printf("\n");
            return 0;
        }

        棧數(shù)組與棧鏈表的代碼實現(xiàn)

        最后呢,我們使用代碼來幫助我們了解一下:

        棧數(shù)組

        數(shù)組棧是一種更為快速的模擬實現(xiàn)棧的方法,這里我們不多說。

        模擬,就是不采用真實的鏈表設(shè)計,轉(zhuǎn)而采用數(shù)組的方式進行模擬操作。

        也就是說這是一種仿真類型的操作,其可以快速的幫助我們構(gòu)建代碼,分析過程,相應(yīng)的實現(xiàn)起來也更加的便捷。

        其代碼如下:

        #include<stdio.h>
        #include<stdlib.h>
        #include<string.h>
        #define maxn 10000
         
        //結(jié)點設(shè)計
        typedef struct stack{
            int data[maxn];
            int top;
        }stack;
         
        //創(chuàng)建
        stack *init(){
            stack *s=(stack *)malloc(sizeof(stack));
            if(s==NULL){
                printf("分配內(nèi)存空間失敗");
                exit(0);
            }
            memset(s->data,0,sizeof(s->data));
            //memset操作來自于庫文件string.h,其表示將整個空間進行初始化
            //不理解可以查閱百度百科https://baike.baidu.com/item/memset/4747579?fr=aladdin
            s->top=0;     //棧的top和bottom均為0(表示為空)
            return s;
        }
         
        //入棧push
        void push(stack *s,int data){
            s->data[s->top]=data;
            s->top++;
        }
         
        //出棧pop
        void pop(stack *s){
            if(s->top!=0){
                s->data[s->top]=0;  //讓其回歸0模擬表示未初始化即可
                s->top--;
            }
        }
         
        //模擬打印棧中元素
        void print_stack(stack *s){
            for(int n=s->top-1;n>=0;n--){
                printf("%d\t",s->data[n]);
            }
            printf("\n");   //習(xí)慣性換行
        }
         
        int main(){
            stack *s=init();
            int input[5]={11,22,33,44,55};  //模擬五個輸入數(shù)據(jù)
            for(int i=0;i<5;i++){
                push(s,input[i]);
            }
            print_stack(s);
            /////////////
            pop(s);
            print_stack(s);
            return 0;
        }

        其編譯結(jié)果如下:

        棧鏈表

        #include <stdio.h>
        #include <stdlib.h>
        //棧的結(jié)點設(shè)計
        //單個結(jié)點設(shè)計,數(shù)據(jù)和下一個指針
        typedef struct node     
        {

            int data; 
            struct node *next;
        } Node;
        //利用上面的結(jié)點創(chuàng)建棧,分為指向頭結(jié)點的top指針和計數(shù)用的count
        typedef struct stack    
        {

            Node *top;
            int count;
        } Link_Stack;
         
        //創(chuàng)建棧
        Link_Stack *Creat_stack()
        {
            Link_Stack *p;
            //p = new Link_Stack;
            p=(Link_Stack*)malloc(sizeof(Link_Stack));
            if(p==NULL){
                printf("創(chuàng)建失敗,即將退出程序");
                exit(0);
            }
         else
         {printf("創(chuàng)建成功\n");
         }
            p->count = 0;
            p->top = NULL;
            return p;
        }
         
        //入棧 push
        Link_Stack *Push_stack(Link_Stack *p, int elem)
        {
            if (p == NULL)
                return NULL;
            Node *temp;
            temp=(Node*)malloc(sizeof(Node));
            //temp = new Node;
            temp->data = elem;
            temp->next = p->top;
            p->top = temp;
            p->count++;
            return p;
        }
         
        //出棧 pop
        Link_Stack *Pop_stack(Link_Stack *p)
        {
            Node *temp;
            temp = p->top;
            if (p->top == NULL)
            {
                printf("錯誤:棧為空");
                return p;
            }
            else
            {
           printf("\npop success");
                p->top = p->top->next;
                free(temp);
                //delete temp;
                p->count--;
                return p;
            }
        }
         
        //遍歷棧:輸出棧中所有元素
        int show_stack(Link_Stack *p)
        {
            Node *temp;
            temp = p->top;
            if (p->top == NULL)
            {
                printf("");
                printf("錯誤:棧為空");
                return 0;
            }
            while (temp != NULL)
            {
                printf("%d\t", temp->data);
                temp = temp->next;
            }
            printf("\n");
            return 0;
        }
         
        int main()
        //用主函數(shù)測試一下功能
         int i;
            Link_Stack *p;
            p = Creat_stack();
            int n = 5;
            int input[6] = {10,20,30,40,50,60};
            /////////////以依次入棧的方式創(chuàng)建整個棧//////////////
            for(i=0;i<n;i++){
                Push_stack(p, input[i]);
            }
            show_stack(p);
            ////////////////////出棧///////////////////////
            Pop_stack(p);
            show_stack(p);
            return 0;
        }

        編譯結(jié)果如下:

        關(guān)于棧的總結(jié)

        棧-它是一種運算受限的線性表,在數(shù)制轉(zhuǎn)換,括號匹配的檢驗,表達式求值等方面都可以使用,并且較為簡便的解決問題。

        今天?;A(chǔ)就講到這里,下一期,我們再見!


        推薦閱讀:


        嵌入式編程專輯
        Linux 學(xué)習(xí)專輯
        C/C++編程專輯

        關(guān)注微信公眾號『技術(shù)讓夢想更偉大』。

        長按前往圖中包含的公眾號關(guān)注

        瀏覽 33
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            女教师被女同学调教成脚奴 | 国产第2页 | 成人不卡网 | 激情婷婷亚洲 | 国产无码中文字幕 | 免费a级黄片 | 一道本一区二区视频 | 国产无遮挡又黄又爽免费视频下载 | 成人无码做爰www欧美粉嫩 | 操逼美女多多 |