問題引入
當(dāng)在瀏覽器頁面打開頁面 a-b-c 之后,點擊瀏覽器的后退按鈕漂佩,就可以查看之前瀏覽過的頁面 b 和 a久信。當(dāng)你后退到頁面 a,點擊前進(jìn)按鈕蝴猪,就可以重新查看頁面 b 和 c调衰。但是,如果你后退到頁面 b 后自阱,點擊了新的頁面 d嚎莉,那就無法再通過前進(jìn)、后退功能查看頁面 c 了沛豌。
棧
當(dāng)某個數(shù)據(jù)集合只涉及在一端插入和刪除數(shù)據(jù)趋箩,并且滿足后進(jìn)先出、先進(jìn)后出的特性加派,我們就應(yīng)該首選“椊腥罚”這種數(shù)據(jù)結(jié)構(gòu)。
以上的場景就可以用這種數(shù)據(jù)結(jié)構(gòu)來實現(xiàn)芍锦。
代碼實現(xiàn)
棧主要包含兩個操作竹勉,入棧和出棧,也就是在棧頂插入一個數(shù)據(jù)和從棧頂刪除一個數(shù)據(jù)醉旦。
棧既可以用數(shù)組來實現(xiàn)饶米,也可以用鏈表來實現(xiàn)。用數(shù)組實現(xiàn)的棧车胡,我們叫作順序棧檬输,用鏈表實現(xiàn)的棧,我們叫作鏈?zhǔn)綏?/strong>匈棘。
1. 順序棧
typedef int Status;
typedef int SElemType; /* SElemType類型根據(jù)實際情況而定丧慈,這里假設(shè)為int */
/* 順序棧結(jié)構(gòu) */
typedef struct
{
SElemType data[MAXSIZE];
int top; /* 用于棧頂指針 */
}SqStack;
/* 構(gòu)造一個空棧S */
Status InitStack(SqStack *S)
{
/* S.data=(SElemType *)malloc(MAXSIZE*sizeof(SElemType)); */
S->top=-1;
return OK;
}
/* 插入元素e為新的棧頂元素 */
Status Push(SqStack *S,SElemType e)
{
if(S->top == MAXSIZE -1) /* 棧滿 */
{
return ERROR;
}
S->top++; /* 棧頂指針增加一 */
S->data[S->top]=e; /* 將新插入元素賦值給棧頂空間 */
return OK;
}
/* 若棧不空,則刪除S的棧頂元素,用e返回其值逃默,并返回OK鹃愤;否則返回ERROR */
Status Pop(SqStack *S,SElemType *e)
{
if(S->top==-1)
return ERROR;
*e=S->data[S->top]; /* 將要刪除的棧頂元素賦值給e */
S->top--; /* 棧頂指針減一 */
return OK;
}
2. 鏈?zhǔn)綏?/h3>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 /* 存儲空間初始分配量 */
typedef int Status;
typedef int SElemType; /* SElemType類型根據(jù)實際情況而定,這里假設(shè)為int */
/* 鏈棧結(jié)構(gòu) */
typedef struct StackNode
{
SElemType data;
struct StackNode *next;
}StackNode,*LinkStackPtr;
typedef struct
{
LinkStackPtr top;
int count;
}LinkStack;
/* 構(gòu)造一個空棧S */
Status InitStack(LinkStack *S)
{
S->top = (LinkStackPtr)malloc(sizeof(StackNode));
if(!S->top)
return ERROR;
S->top=NULL;
S->count=0;
return OK;
}
/* 插入元素e為新的棧頂元素 */
Status Push(LinkStack *S,SElemType e)
{
LinkStackPtr s=(LinkStackPtr)malloc(sizeof(StackNode));
s->data=e;
s->next=S->top; /* 把當(dāng)前的棧頂元素賦值給新結(jié)點的直接后繼完域,見圖中① */
S->top=s; /* 將新的結(jié)點s賦值給棧頂指針软吐,見圖中② */
S->count++;
return OK;
}
/* 若棧不空,則刪除S的棧頂元素吟税,用e返回其值凹耙,并返回OK;否則返回ERROR */
Status Pop(LinkStack *S,SElemType *e)
{
LinkStackPtr p;
if(StackEmpty(*S))
return ERROR;
*e=S->top->data;
p=S->top; /* 將棧頂結(jié)點賦值給p肠仪,見圖中③ */
S->top=S->top->next; /* 使得棧頂指針下移一位肖抱,指向后一結(jié)點,見圖中④ */
free(p); /* 釋放結(jié)點p */
S->count--;
return OK;
}
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 /* 存儲空間初始分配量 */
typedef int Status;
typedef int SElemType; /* SElemType類型根據(jù)實際情況而定,這里假設(shè)為int */
/* 鏈棧結(jié)構(gòu) */
typedef struct StackNode
{
SElemType data;
struct StackNode *next;
}StackNode,*LinkStackPtr;
typedef struct
{
LinkStackPtr top;
int count;
}LinkStack;
/* 構(gòu)造一個空棧S */
Status InitStack(LinkStack *S)
{
S->top = (LinkStackPtr)malloc(sizeof(StackNode));
if(!S->top)
return ERROR;
S->top=NULL;
S->count=0;
return OK;
}
/* 插入元素e為新的棧頂元素 */
Status Push(LinkStack *S,SElemType e)
{
LinkStackPtr s=(LinkStackPtr)malloc(sizeof(StackNode));
s->data=e;
s->next=S->top; /* 把當(dāng)前的棧頂元素賦值給新結(jié)點的直接后繼完域,見圖中① */
S->top=s; /* 將新的結(jié)點s賦值給棧頂指針软吐,見圖中② */
S->count++;
return OK;
}
/* 若棧不空,則刪除S的棧頂元素吟税,用e返回其值凹耙,并返回OK;否則返回ERROR */
Status Pop(LinkStack *S,SElemType *e)
{
LinkStackPtr p;
if(StackEmpty(*S))
return ERROR;
*e=S->top->data;
p=S->top; /* 將棧頂結(jié)點賦值給p肠仪,見圖中③ */
S->top=S->top->next; /* 使得棧頂指針下移一位肖抱,指向后一結(jié)點,見圖中④ */
free(p); /* 釋放結(jié)點p */
S->count--;
return OK;
}
空間復(fù)雜度:
不管是順序棧還是鏈?zhǔn)綏R炀桑覀兇鎯?shù)據(jù)只需要一個大小為 n 的數(shù)組就夠了意述。在入棧和出棧過程中,只需要一兩個臨時變量存儲空間吮蛹,所以空間復(fù)雜度[1]是 O(1)荤崇。
時間復(fù)雜度:
時間復(fù)雜度也同樣,不管是順序棧還是鏈?zhǔn)綏Fヤ蹋霔L焓浴⒊鰲V簧婕皸m攤€別數(shù)據(jù)的操作槐壳,所以時間復(fù)雜度都是 O(1)然低。
[1]:這里存儲數(shù)據(jù)需要一個大小為 n 的數(shù)組,并不是說空間復(fù)雜度就是 O(n)务唐。因為雳攘,這 n 個空間是必須的,無法省掉枫笛。所以我們說空間復(fù)雜度的時候吨灭,是指除了原本的數(shù)據(jù)存儲空間外,算法運行還需要額外的存儲空間刑巧。
應(yīng)用場景
- 函數(shù)調(diào)用棧
- 表達(dá)式求知
- 括號匹配