數據結構(二)棧與隊列---棧的了解和棧的順序存儲結構和實現


(一)棧的定義

棧是一種重要的線性結構。是我們前面講過的線性表的一種具體形式
棧是限定僅在表尾進行插入和刪除操作的線性表
我們把允許插入和刪除的一端稱為棧頂top,另一端稱為棧底bottom,不含任何元素的棧稱為空棧。棧又稱為后進先出(Last In First Out)的線性表,簡稱LIFO
棧的插入操作,叫做進棧,也稱為壓棧,入棧
棧的刪除操作,叫做出棧,也稱為彈棧

(二)棧的抽象數據類型

ADT 棧(stack)
Data
    同線性表。元素具有相同的類型,相鄰元素具有前驅和后繼的關系。

Operation
    InitStack( *s): 初始化操作,建立一個空棧
    ClearStack( *s): 將棧清空
    StackEmpty( s): 若棧存在,返回true,否則返回false
    StackLength( s): 返回棧S的元素個數

    GetTop( s, *e): 若是棧存在且非空,用e返回S的棧頂元素
    Push( *s, e):若是棧存在,則插入新的元素e到棧S中並成為棧頂元素
    Pop( *s, *e):若是棧存在且非空,刪除棧頂元素,並用e返回其值
    DestroyStack( *s): 若是棧存在,則銷毀他
endADT

注意:

由於棧本身就是一個線性表,那么我們講的線性表的順序存儲和鏈式存儲,對於棧來說,都是適用的

(三)棧的順序存儲結構

typedef struct
{
    ElemType *base;    //棧底指針
    ElemType *top;    //棧頂指針
    int stackSize;    //最大容量,這是可修改的
}sqStack;

(四)實現棧之前的預備知識

(1)malloc函數獲取的內存,內存空間上是連續的

malloc出來的空間,只是在虛擬內存中是連續的。而從實際的物理空間到虛擬內存空間還有一個映射的關系。
這個映射是由操作系統來控制的,一般情況下,從虛擬地址無法反查到物理地址。對於連續的虛擬地址空間,也就無法得知是否物理連續。
但由於映射的不確定性,當申請一段內存空間,尤其是比較大的內存長度情況下,物理地址不連續的可能性還是相當大的。 事實上,大多數的編程不需要關注物理空間是否連續。

(2)不同類型指針的步長增長問題

對於不同類型的指針,雖然指針在內存中的大小都是4字節,
但是他們的增長的地址步長與指針本身大小無關,而是與內部儲存數據類型大小有關。
例如:
int *a=(int*)malloc(100*size(int))
int b,c;
b=a;
c=a++;
b=4236536 //這是10進制下的地址
c=4236540 //增長了一個int字節大小的步長

char *base = (char *)malloc(sizeof(char) * 100);
addr1 = base;
addr2 = base+1;
------------------
addr1=5350647
addr2=5350648  //這里增長了一個char類型字節大小的步長
int *base, *top;
base = (int *)malloc(sizeof(int) * 100);
top = base + 100;
printf("size:%d\n",top - base)  //重點:兩個指針之間相減,所得到的不是地址大小之差,而是其中含有的元素個數,是100,若是我們想要知道地址之差,可以使用int強制轉換十六進制地址為一個十進制數進行減法運算,結果是400

(3)指針和所指向的數據中間的關系

我們存儲的數據在指針所指向的位置開始,占用了相關大小的字節去存放數據。
所以當我們創建棧的時候,我們的棧頂指針是不能直接讀取,我們往往需要先將他降一,然后才能讀取那塊內存空間獲取數據

例如:我們要獲取棧頂數據11,我們就需要先將棧頂退一,然后才能讀取到數據

(4)realloc函數,再分配空間。用法和誤區 

realloc 
       原型:extern void *realloc(void *mem_address, unsigned int newsize); 
       用法:#include <stdlib.h> 有些編譯器需要#include <alloc.h> 
       功能:改變mem_address所指內存區域的大小為newsize長度。 
       說明:如果重新分配成功則返回指向被分配內存的指針,否則返回空指針NULL。 
                 當內存不再使用時,應使用free()函數將內存塊釋放。 
       注意:這里原始內存中的數據還是保持不變的。 
1、如果有足夠空間用於擴大mem_address指向的內存塊,則分配額外內存,並返回mem_address 
這里說的是“擴大”,我們知道,realloc是從堆上分配內存的,當擴大一塊內存空間時, realloc()試圖直接從堆上現存的數據后面的那些字節中獲得附加的字節,如果能夠滿足,自然天下太平。也就是說,如果原先的內存大小后面還有足夠的空閑空間用來分配,加上原來的空間大小= newsize。那么就ok。得到的是一塊連續的內存。 
2、如果原先的內存大小后面沒有足夠的空閑空間用來分配,那么從堆中另外找一塊newsize大小的內存。 
並把原來大小內存空間中的內容復制到newsize中。返回新的mem_address指針。(數據被移動了)。 
老塊被放回堆上。 

注意:

1、返回值可能與ptr的值不同,如果是不同的話,那么realloc函數完成后,ptr指向的舊內存已被free掉了,會自動為我們釋放,所以我們不需要關心。只需要釋放新的內存地址即可 2、如果返回NULL值,則分配不成功,而原來的ptr指向的內存還沒有被free掉,要求程序顯式free.

(五)棧的順序存儲結構實現

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define STACK_INIT_SIZE 100    //定義棧的初始大小
#define STACK_INCR_SIZE 10    //定義棧的增長大小

typedef int ElemType;
typedef int Status;

typedef struct
{
    ElemType *base;    //棧底指針
    ElemType *top;    //棧頂指針
    int stackSize;    //最大容量,這是可修改的
}sqStack;

//四個基礎操作
Status InitStack(sqStack *s);    //初始化操作,建立一個空棧
Status ClearStack(sqStack *s);    //將棧清空
Status StackEmpty(sqStack s);    //若棧存在,返回true,否則返回false
int StackLength(sqStack s);        //返回棧S的元素個數

Status GetTop(sqStack s, ElemType *e);    //若是棧存在且非空,用e返回S的棧頂元素
Status Push(sqStack *s, ElemType e);    // 若是棧存在,則插入新的元素e到棧S中並成為棧頂元素
Status Pop(sqStack *s, ElemType *e);    //若是棧存在且非空,刪除棧頂元素,並用e返回其值
Status DestroyStack(sqStack *s);        //若是棧存在,則銷毀他

int main()
{
    sqStack sk;
    int i;
    ElemType e;
    sk.base = sk.top = NULL;    //用於判斷是否存在
    //初始化空棧
    printf("1.InitStack\n");
    InitStack(&sk);
    printf("2.Push 1-5\n");
    for (i = 1; i <= 5; i++)
        Push(&sk, i);
    printf("3.Pop number for three times\n");
    for (i = 1; i <= 3;i++)
    {
        Pop(&sk, &e);
        printf("Pop %d: %d\n",i, e);
    }
    GetTop(sk, &e);
    printf("4.Get Top:%d\n",e);
    printf("5.Push 6-10\n");
    for (i = 6; i <= 10; i++)
        Push(&sk, i);
    printf("6.Get stack length:%d\n", StackLength(sk));
    printf("7.Pop number for six times\n");
    for (i = 1; i <= 6; i++)
    {
        Pop(&sk, &e);
        printf("Pop %d: %d\n",i, e);
    }
    if (!StackEmpty(sk))
    {
        printf("8.Stack is not Empty\n");
        ClearStack(&sk);
        printf("9.Stack is Clear\n");
    }
    printf("10.Stack Empty:%d\n",StackEmpty(sk));
    printf("11.destroy Stack");
    DestroyStack(&sk);

    system("pause");
    return 0;
}

//初始化操作,建立一個空棧
Status InitStack(sqStack *s)
{
    s->base = (ElemType *)malloc(STACK_INIT_SIZE*sizeof(ElemType));
    if (!s->base)
        return ERROR;
    s->top = s->base;    //最開始,棧頂就是棧底
    s->stackSize = STACK_INIT_SIZE;
    return OK;
}

//將棧清空,將棧頂指針移動到棧底即可,容量大小不要修改,數據不需要清空,數據入棧會覆蓋
Status ClearStack(sqStack *s)
{
    if (s == NULL)
        return ERROR;
    s->top = s->base;
    return OK;
}

//若棧存在,返回true,否則返回false
Status StackEmpty(sqStack s)
{
    if (s.base == s.top)
        return TRUE;
    return FALSE;
}

//返回棧S的元素個數
int StackLength(sqStack s)
{
    int length = s.top - s.base;    //指針之間運算,是按照其中數據大小字節來算的
    return length;
}

//若是棧存在且非空,用e返回S的棧頂元素,注意:只是獲取棧頂數據,不出棧
Status GetTop(sqStack s, ElemType *e)
{
    if (!e || StackEmpty(s) || !s.base)
        return ERROR;
    *e = *(s.top - 1);
    return OK;
}

//入棧操作:若是棧存在,則插入新的元素e到棧S中並成為棧頂元素
Status Push(sqStack *s, ElemType e)
{
    ElemType* newStack;
    if (!s->base)
        return ERROR;

    if (s->top-s->base>=s->stackSize)    //棧滿,需要再分配
    {
        newStack = (ElemType *)realloc(s->base, (s->stackSize + STACK_INCR_SIZE)*sizeof(ElemType));    //重新分配大小
        if (!newStack)    //若是分配失敗,會返回NULL
        {
            free(s->base);
            exit(0);    //分配失敗,直接退出
        }
        s->base = newStack;
        //分配后需要將棧頂指針進行移動到新的位置
        s->top = s->base + s->stackSize;
    }
    *(s->top) = e;
    s->top++;
    return OK;
}

//若是棧存在且非空,刪除棧頂元素(只需要將棧頂指針下移即可),並用e返回其值
Status Pop(sqStack *s, ElemType *e)
{
    if (!s->base || !e || StackEmpty(*s))
        return ERROR;
    *e = *(--s->top);
    return OK;
}

//若是棧存在,則銷毀他(直接將棧底指針釋放即可,置為空)
Status DestroyStack(sqStack *s)
{
    if (!s->base)    //若是棧存在
    {
        s->stackSize = 0;
        free(s->base);
        s->base = s->top = NULL;
    }
    return OK;
}

(六)應用:進制轉換

Status Bin2Dec(sqStack* s,int *val);    //二進制轉十進制
Status Bin2Oct(sqStack* s, sqStack* sv);    //二進制轉八進制
Status Bin2Hex(sqStack* s, sqStack* sv);    //二進制轉十六進制

int main()
{
    sqStack sk;
 sqStack valsk;  //接收轉換為8進制或者16進制的數,需要再使用一個棧 int dec;  //接收轉換為10進制數值 char ch;
    ElemType e;
    sk.base = sk.top = NULL;    //用於存放二進制字符串
    valsk.base = valsk.top = NULL;    //用於存放八進制和十六進制值
    //初始化空棧
    InitStack(&sk);
    InitStack(&valsk);
    scanf("%c", &ch);
    while (ch!='#')
    {
        Push(&sk, ch);
        scanf("%c", &ch);
    }
    getchar();    //消除鍵盤緩沖區中的回車符

   //這里修改后可以測試其他進制轉換,注意:轉換10進制不需要用到第二個棧 if (Bin2Hex(&sk, &valsk)) while (!StackEmpty(valsk)) { Pop(&valsk, &ch); printf("%c", ch); }

    DestroyStack(&sk);
    DestroyStack(&valsk);

    system("pause");
    return 0;
}

//二進制轉十進制
Status Bin2Dec(sqStack* s, int *val)
{
    int i,key,length,v=0;
    char ch;

    if (!val || StackEmpty(*s))
        return ERROR;

    length = StackLength(*s);

    for (i = 0; i < length;i++)
    {
        Pop(s, &ch);
        key = ch - 48;
        v += key*pow(2, i);
    }
    *val = v;
    return OK;
}

//二進制轉八進制
Status Bin2Oct(sqStack* s, sqStack* sv)
{
    char ord[3] = { 0 };
    char ch;
    int i,length,val;

    if (!s || !sv)
        return ERROR;

    if (!StackEmpty(*sv))
        ClearStack(sv);

    while (!StackEmpty(*s))
    {
        memset(ord, '0', 3);
        val = 0;
        length = StackLength(*s);
        if (length >= 3)
            for (i = 2; i >= 0; i--)
                Pop(s, &ord[i]);
        else
            for (i = 2; i >= 3 - length; i--)
                Pop(s, &ord[i]);

        for (i = 0; i < 3;i++)
            val += (ord[2 - i] - 48)*pow(2, i);
        Push(sv, (char)(val+48));
    }
    return OK;
}

//二進制轉十六進制
Status Bin2Hex(sqStack* s, sqStack* sv)
{
    char hex[4] = { 0 };
    char ch;
    int i, length, val;

    if (!s || !sv)
        return ERROR;

    if (!StackEmpty(*sv))
        ClearStack(sv);

    while (!StackEmpty(*s))
    {
        memset(hex, '0', 4);
        val = 0;
        length = StackLength(*s);
        if (length >= 4)
            for (i = 3; i >= 0; i--)
                Pop(s, &hex[i]);
        else
            for (i = 3; i >= 4 - length; i--)
                Pop(s, &hex[i]);

        for (i = 0; i < 4; i++)
            val += (hex[3 - i] - 48)*pow(2, i);
        if (val < 10)
            Push(sv, (char)(val + 48));
        else
            Push(sv, 'A' + val - 10);

    }
    return OK;
}

(七)棧的順序存儲實現另法:使用數組

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 100

typedef int ElemType;
typedef int Status;

typedef struct
{
    ElemType data[MAXSIZE];
    int top;
}sqStack;

//四個基礎操作
Status InitStack(sqStack *s);    //初始化操作,建立一個空棧
Status ClearStack(sqStack *s);    //將棧清空
Status StackEmpty(sqStack s);    //若棧存在,返回true,否則返回false
int StackLength(sqStack s);        //返回棧S的元素個數

Status GetTop(sqStack s, ElemType *e);    //若是棧存在且非空,用e返回S的棧頂元素
Status Push(sqStack *s, ElemType e);    // 若是棧存在,則插入新的元素e到棧S中並成為棧頂元素
Status Pop(sqStack *s, ElemType *e);    //若是棧存在且非空,刪除棧頂元素,並用e返回其值
Status DestroyStack(sqStack *s);        //若是棧存在,則銷毀他

int main()
{
    sqStack sk;
    int i;
    ElemType e;

    //初始化空棧
    printf("1.InitStack\n");
    InitStack(&sk);
    printf("2.Push 1-5\n");
    for (i = 1; i <= 5; i++)
        Push(&sk, i);
    printf("3.Pop number for three times\n");
    for (i = 1; i <= 3;i++)
    {
        Pop(&sk, &e);
        printf("Pop %d: %d\n",i, e);
    }
    GetTop(sk, &e);
    printf("4.Get Top:%d\n",e);
    printf("5.Push 6-10\n");
    for (i = 6; i <= 10; i++)
        Push(&sk, i);
    printf("6.Get stack length:%d\n", StackLength(sk));
    printf("7.Pop number for six times\n");
    for (i = 1; i <= 6; i++)
    {
        Pop(&sk, &e);
        printf("Pop %d: %d\n",i, e);
    }
    if (!StackEmpty(sk))
    {
        printf("8.Stack is not Empty\n");
        ClearStack(&sk);
        printf("9.Stack is Clear\n");
    }
    printf("10.Stack Empty:%d\n",StackEmpty(sk));
    printf("11.destroy Stack");
    DestroyStack(&sk);

    system("pause");
    return 0;
}

//初始化操作,建立一個空棧
Status InitStack(sqStack *s)
{
    if (!s)
        return ERROR;
    memset(s->data, 0, MAXSIZE*sizeof(ElemType));
    s->top = -1;
    return OK;
}

//將棧清空,將棧頂指針移動到棧底即可,數據不需要清空,數據入棧會覆蓋
Status ClearStack(sqStack *s)
{
    if (!s)
        return ERROR;
    s->top = -1;
    return OK;
}

//若棧存在,返回true,否則返回false
Status StackEmpty(sqStack s)
{
    if (s.top == -1)
        return OK;
    return FALSE;
}

//返回棧S的元素個數
int StackLength(sqStack s)
{
    return s.top+1;
}

//若是棧存在且非空,用e返回S的棧頂元素,注意:只是獲取棧頂數據,不出棧
Status GetTop(sqStack s, ElemType *e)
{
    if (s.top = -1||!e)
        return ERROR;
    *e = s.data[s.top];
    return OK;
}

//入棧操作:若是棧存在,則插入新的元素e到棧S中並成為棧頂元素
Status Push(sqStack *s, ElemType e)
{
    if (s->top + 1 == MAXSIZE||!s)
        return ERROR;
    s->top++;
    s->data[s->top] = e;
    return OK;
}

//若是棧存在且非空,刪除棧頂元素(只需要將棧頂指針下移即可),並用e返回其值
Status Pop(sqStack *s, ElemType *e)
{
    if (s->top == -1||!s||!e)
        return ERROR;
    *e = s->data[s->top];
    s->top--;
    return OK;
}

//若是棧存在,則銷毀他,數據清空
Status DestroyStack(sqStack *s)
{
    if (!s)
        return ERROR;
    memset(s->data, 0, MAXSIZE*sizeof(ElemType));
    s->top = -1;
    return OK;
}

引申:兩棧共享空間

對於我們使用數組來構造順序棧,有一個很大的缺陷,就是需要事先確定數組的存儲空間大小,不夠的話擴容不方便,太多了又過於浪費空間。
於是設計出來合適的大小數組,將他的空間從兩頭分別當做一個棧。就可以最大限度的利用數組空間。
例如:一個棧需要的空間大概為50-150,多數情況是在100以下,有少數情況會超過100。
那么當我們使用兩個棧時,若是聲明兩個150空間的數組。則空間浪費較多。
不如一次聲明200空間大小供兩個棧共同使用。雖然有滿棧的情況,不過出現情況不大。而且會最大程度利用了棧的空間。

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 10

typedef int ElemType;
typedef int Status;

//兩棧共享空間結構
typedef struct
{
    ElemType data[MAXSIZE];
    int top1;    //棧1 棧頂指針 指向數組開始 從做向右
    int top2;    //棧2 棧頂指針 指向數組結尾 從右向左
}sqDoubleStack;

//四個基礎操作
Status InitStack(sqDoubleStack *s);    //初始化操作,建立一個空棧
Status ClearStack(sqDoubleStack *s, int stackNumber);    //將棧清空
Status StackEmpty(sqDoubleStack s, int stackNumber);    //若棧存在,返回true,否則返回false
int StackLength(sqDoubleStack s, int stackNumber);        //返回棧S的元素個數

Status GetTop(sqDoubleStack s, ElemType *e, int stackNumber);    //若是棧存在且非空,用e返回S的棧頂元素
Status Push(sqDoubleStack *s, ElemType e, int stackNumber);    // 若是棧存在,則插入新的元素e到棧S中並成為棧頂元素
Status Pop(sqDoubleStack *s, ElemType *e, int stackNumber);    //若是棧存在且非空,刪除棧頂元素,並用e返回其值
Status DestroyStack(sqDoubleStack *s);        //若是棧存在,則銷毀他

int main()
{
    sqDoubleStack sk;
    int i;
    Status st;
    ElemType e;

    //初始化空棧
    printf("1.InitStack\n");
    InitStack(&sk);
    printf("2.Push 1-10\n");
    for (i = 1; i <= 11; i++)
    {
        st=Push(&sk, i, i % 2 + 1);
        if (st == ERROR)
            printf("2.Push %d to stack-%d failure!\n", i, i % 2 + 1);
    }
    printf("3.Pop number for three times\n");
    for (i = 1; i <= 5; i++)
    {
        Pop(&sk, &e,i%2+1);
        printf("Pop stack-%d: %d\n", i%2+1, e);
    }
    GetTop(sk, &e,1);
    printf("4.Get stack-1 Top:%d\n", e);
    GetTop(sk, &e, 2);
    printf("4.Get stack-2 Top:%d\n", e);

    printf("5.Get stack-1 length:%d\n", StackLength(sk,1));
    if (!StackEmpty(sk,1))
    {
        printf("8.Stack-1 is not Empty\n");
        ClearStack(&sk,1);
        printf("9.Stack-1 is Clear\n");
    }

    printf("5.Get stack-2 length:%d\n", StackLength(sk, 2));
    if (!StackEmpty(sk, 2))
    {
        printf("8.Stack-2 is not Empty\n");
        ClearStack(&sk, 2);
        printf("9.Stack-2 is Clear\n");
    }
    
    printf("10.Stack-1 Empty:%d\n", StackEmpty(sk,1));
    printf("10.Stack-2 Empty:%d\n", StackEmpty(sk, 2));
    printf("11.destroy Stack");
    DestroyStack(&sk);

    system("pause");
    return 0;
}

//初始化操作,建立一個空棧
Status InitStack(sqDoubleStack *s)
{
    if (!s)
        return ERROR;
    memset(s->data, 0, MAXSIZE*sizeof(ElemType));
    s->top1 = -1;
    s->top2 = MAXSIZE;
    return OK;
}

//將棧清空,stackNumber為0,兩個都清空,為1清空棧1,2清空棧2
Status ClearStack(sqDoubleStack *s, int stackNumber)
{
    if (!s)
        return ERROR;
    if (stackNumber == 0)
    {
        s->top1 = -1;
        s->top2 = MAXSIZE;
    }
    else if (stackNumber==1)
    {
        s->top1 = -1;
    }
    else if (stackNumber==2)
    {
        s->top2 = MAXSIZE;
    }
    return OK;
}

//若兩個棧都不存在,返回true,否則返回false
Status StackEmpty(sqDoubleStack s, int stackNumber)
{
    if (stackNumber == 0)
    {
        if (s.top1 == -1 && s.top2 == MAXSIZE)
            return OK;
    }
    else if (stackNumber == 1)
    {
        if (s.top1 == -1)
            return OK;
    }
    else if (stackNumber == 2)
    {
        if (s.top2 == MAXSIZE)
            return OK;
    }
    return FALSE;
}

//返回棧S的元素個數,是指兩個棧的總長
int StackLength(sqDoubleStack s,int stackNumber)
{
    int length = 0;
    if (stackNumber == 0)
        length=(s.top1 + 1) + (MAXSIZE - s.top2);
    else if (stackNumber == 1)
        length = s.top1 + 1;
    else if (stackNumber == 2)
        length = MAXSIZE - s.top2;
    return length;
}

//若是棧存在且非空,用e返回S的棧頂元素,注意:只是獲取棧頂數據,不出棧
Status GetTop(sqDoubleStack s, ElemType *e,int stackNumber)
{
    if (!e)
        return ERROR;
    if (stackNumber == 1)
        if (s.top1 == -1)
            return ERROR;
        else
            *e = s.data[s.top1];
    else if (stackNumber == 2)
        if (s.top2 == MAXSIZE)
            return ERROR;
        else
            *e = s.data[s.top2];
    return OK;
}

//入棧操作:若是棧存在,則插入新的元素e到棧S中並成為棧頂元素
Status Push(sqDoubleStack *s, ElemType e, int stackNumber)
{
    if (!s)
        return ERROR;
    if (s->top1 + 1 == s->top2)    //棧滿,不允許插入
        return ERROR;
    
    if (stackNumber == 1)
        s->data[++s->top1] = e;
    else if (stackNumber==2)
        s->data[--s->top2] = e;
    
    return OK;
}

//若是棧存在且非空,刪除棧頂元素(只需要將棧頂指針下移即可),並用e返回其值
Status Pop(sqDoubleStack *s, ElemType *e, int stackNumber)
{
    if (StackEmpty(*s, stackNumber)||!s || !e)
        return ERROR;
    
    if (stackNumber == 1)
        *e = s->data[s->top1--];
    else if (stackNumber==2)
        *e = s->data[s->top2++];
    return OK;
}

//若是棧存在,則銷毀他,兩個棧都銷毀
Status DestroyStack(sqDoubleStack *s)
{
    if (!s)
        return ERROR;
    memset(s->data, 0, MAXSIZE*sizeof(ElemType));
    s->top1 = -1;
    s->top2 = MAXSIZE;
    return OK;
}

(八)兩種順序結構棧的比較

方法一的空間是malloc出來的一塊連續空間,操作稍微復雜些。但是當棧滿時,可以進行擴展。
方法二除了使用簡單,對於棧的擴展方面欠缺。
推薦第一種,了解第二種即可

(九)棧的應用:括號匹配

對於()[]{}都是正確的[),{],(}都是匹配失敗的,注意:對於引號里面的括號不進行匹配,()[]'(]'()是正確的
int main()
{
    sqStack sk;
    ElemType e;
    char ch;
    sk.base = sk.top = NULL;    //用於判斷是否存在
    //初始化空棧,用於存放()[]{}''""這幾個數據,的左半邊進行匹配
    InitStack(&sk);
    scanf("%c", &ch);
    while (ch!='#')
    {
        if (GetTop(sk, &e))
        {
            if ((e == '"'&&ch != '"') || (e == '\''&&ch != '\''))    //若是在單雙引號之間的括號全部舍去
                goto GS;
            if ((e == '"'&&ch == '"') || (e == '\''&&ch == '\''))    //匹配單雙引號,優先級是最高的
            {
                Pop(&sk, &e);    //彈出單雙引號
                goto GS;
            }
            if ((e == '('&&ch == ')') || (e == '['&&ch == ']') || (e == '{'&&ch == '}'))
            {
                Pop(&sk, &e);    //彈出匹配好的括號
                goto GS;
            }
            if ((ch == ')'&&e != '(') || (ch == ']'&&e != '[') || (ch == '}'&&e != '{'))    //這是當我們獲取的右半邊括號與棧頂不匹配時,直接退出,退出時棧不為空
                break;
        }
        else   //沒有棧頂元素
        {
            if (ch == ')' || ch == ']' || ch == '}')    //沒有棧頂元素時,若是我們獲取的括號是右半邊直接匹配失敗
            {
                Push(&sk, ch);    //這里必須放一個東西入棧,以保證不為空,為一會判斷做准備,至於入棧的數據隨意
                break;
            }
        }
        if (ch == '('||ch=='['||ch=='{'||ch=='\'' || ch == '"')
            Push(&sk, ch);
    GS:
        scanf("%c", &ch);
    }
    getchar();
    
    if (StackEmpty(sk))
        printf("match success!");
    else
        printf("match failure!");
    system("pause");
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM