一、棧 分爲順序棧和鏈棧 對應數組和鏈表數組
top指向棧頂元素,設置空棧爲-1;存在一個元素時top=0spa
棧的長度爲StackSize.net
定義棧的結構體:指針
1 #include "stdio.h" 2 3 /* 存儲空間初始分配量 */ 4 #define MAXSIZE 20 5 6 /* SElemType類型根據實際狀況而定,這裏假設爲int */ 7 typedef int SElemType; 8 9 /* 順序棧結構 */ 10 typedef struct 11 { 12 SElemType data[MAXSIZE]; 13 int top; /* 用於棧頂指針 */ 14 }SqStack; 15 16 int main() 17 { 18 }
進棧操做:pushcode
1 int Push(SqStack * S, SElemType e){ 2 if(S->top == MAXSIZE-1){ 3 //棧滿 4 return 0; 5 } 6 S->top++; 7 S->data[S->top] = e; 8 return 1; 9 }
初始化一個空棧:blog
//初始化棧 int InitStack(SqStack S){ S->top = -1; return 1; }
棧的遍歷:內存
1 /* 從棧底到棧頂依次對棧中每一個元素顯示 */ 2 Status StackTraverse(SqStack S) 3 { 4 int i; 5 i=0; 6 while(i<=S.top) 7 { 8 visit(S.data[i++]); 9 } 10 printf("\n"); 11 return OK; 12 } 13 14 Status visit(SElemType c) 15 { 16 printf("%d ",c); 17 return OK; 18 }
注:S->top表明着棧對應數組的下標0,1,2 。。。get
出棧:it
1 int Pop(SqStack* S, SElemType* e){ 2 if(-1 == S->top){ 3 return 0; 4 } 5 *e = S->data[S->top]; 6 S->top--; 7 return 1; 8 }
獲取棧頂元素:io
1 /* 若棧不空,則用e返回S的棧頂元素,並返回OK;不然返回ERROR */ 2 Status GetTop(SqStack S,SElemType *e) 3 { 4 if (S.top==-1) 5 return ERROR; 6 else 7 *e=S.data[S.top]; 8 return OK; 9 }
判斷棧是否爲空:
1 |
/* 若棧S爲空棧,則返回TRUE,不然返回FALSE */ |
2 |
Status StackEmpty(SqStack S) |
3 |
{ |
4 |
if (S.top==-1) |
5 |
return TRUE; |
6 |
else |
7 |
return FALSE; |
8 |
} |
置空棧:
1 |
/* 把S置爲空棧 */ |
2 |
Status ClearStack(SqStack *S) |
3 |
{ |
4 |
S->top=-1; |
5 |
return OK; |
6 |
} |
二、鏈棧
鏈棧對應不含頭結點的單鏈表
top表明指向棧頂的指針,這裏和鏈表中的next合併爲一個,當top=null時,鏈棧爲空
定義鏈棧的結構體:
下面是單鏈表的結構體:
1 typedef struct Node 2 { 3 ElemType data; 4 struct Node *next; 5 }Node; 6 typedef struct Node *LinkList; /* 定義LinkList */
類似的鏈棧的結構體爲:
1 /* 鏈棧結構 */ 2 typedef struct StackNode 3 { 4 SElemType data; 5 struct StackNode *next; 6 } StackNode,*LinkStackPtr;
這只是鏈棧一個節點的定義,還須要添加鏈棧的棧頂指針:
1 typedef int Status; 2 /* SElemType類型根據實際狀況而定,這裏假設爲int */ 3 typedef int SElemType; 4 5 /* 鏈棧結構 */ 6 typedef struct StackNode 7 { 8 SElemType data; 9 struct StackNode *next; 10 } StackNode,*LinkStackPtr; 11 12 typedef struct 13 { 14 LinkStackPtr top; 15 int count; 16 } LinkStack;
其中count是用來計算棧中元素的個數的,也能夠根據須要添加屬性等
入棧,其實就是添加新的節點,下面這張圖描述的很清楚:
實際上就兩步:一、將新的節點next指向原棧頂元素 二、將top指針指向新的節點
1 int Push(LinkStack* L, SElemType e){ 2 //首先分配節點 3 LinkStackPtr p = (LinkStackPtr)malloc(sizeof(StackNode)); 4 p->data = e; 5 p->next = S->top; 6 S->top = p; 7 S->count++; 8 return 1; 9 }
初始化空棧:條件count=0,且top爲null
1 /* 構造一個空棧S */ 2 Status InitStack(LinkStack *S) 3 { 4 S->top = (LinkStackPtr)malloc(sizeof(StackNode)); 5 if(!S->top) 6 return ERROR;//分配失敗 7 S->top=NULL; 8 S->count=0; 9 return OK; 10 }
遍歷的過程和鏈表徹底相似,這裏再也不贅述:
1 Status StackTraverse(LinkStack S) 2 { 3 LinkStackPtr p; 4 p=S.top; 5 while(p) 6 { 7 visit(p->data); 8 p=p->next; 9 } 10 printf("\n"); 11 return OK; 12 } 13 14 Status visit(SElemType c) 15 { 16 printf("%d ",c); 17 return OK; 18 }
出棧操做:這裏主要注意一點就是刪除的節點要釋放掉 核心代碼就是S->top = S->top->next;
1 /* 若棧不空,則刪除S的棧頂元素,用e返回其值,並返回OK;不然返回ERROR */ 2 Status Pop(LinkStack *S,SElemType *e) 3 { 4 LinkStackPtr p; 5 if(StackEmpty(*S)) 6 return ERROR; 7 *e=S->top->data; 8 p=S->top; /* 將棧頂結點賦值給p,見圖中① */ 9 S->top=S->top->next; /* 使得棧頂指針下移一位,指向後一結點,見圖中② */ 10 free(p); /* 釋放結點p */ 11 S->count--; 12 return OK; 13 }
注:這裏的Status是預約義的,這裏簡化表示int
置空鏈棧會比順序棧稍微複雜一些:置空順序棧只需一步S->top = -1便可,而對於鏈棧置空實質上就是刪除整個鏈表全部的節點,這裏關鍵的問題就是移動待刪除節點指針到下一個位置後,無法直接free掉,這樣提及來很差理解,直接看代碼:
1 /* 把S置爲空棧 */ 2 Status ClearStack(LinkStack *S) 3 { 4 LinkStackPtr p,q; 5 p=S->top; 6 while(p) 7 { 8 q=p; 9 p=p->next; 10 free(q); 11 } 12 S->count=0; 13 return OK; 14 }
其實就是先將待刪除節點付給一個臨時指針,而後當前指針移動到下一個位置後,就能夠將這個臨時指針給free掉
那這裏來分析一下順序棧和鏈棧的區別:二者的時間複雜度都爲O(1)
順序棧定位元素更加方便,需提早分配內存區域;鏈棧在內存充足的狀況下大小是無限的,存取定位沒有順序棧快,每一個節點還有指針域,某種程度上增長了空間開銷
因此根據不一樣狀況選擇