栈(Stack)是限定仅在表尾进行插入或删除操作的线性表。通常称其表尾为栈顶(top),表头端称为栈底( bottom)。按栈的存储方式可以分为顺序栈、链式栈。
一、顺序表栈
1 #include <stdio.h> 2 #include <malloc.h> 3 4 #define OVERFLOW -1 5 #define OK 1 6 #define ERROR 0 7 #define STACK_INIT_SIZE 100 //存储空间初始分配量 8 #define STACKINCREMENT 10//存储空间分配增量 9 10 typedef int SElemType,Status; 11 /* 顺序栈结构体 */ 12 typedef struct { 13 SElemType *base; //栈底指针 14 SElemType *top; //栈顶指针 15 int stacksize; 16 }SqStack; 17 18 /* 构造一个空栈 */ 19 Status InitStack (SqStack &S ){ 20 S.base = (SElemType*) malloc(STACK_INIT_SIZE*sizeof (SElemType)); 21 if (! S.base) exit(OVERFLOW);//存储分配失败 22 S.top =S.base; 23 S.stacksize = STACK_INIT_SIZE; 24 return OK; 25 } 26 27 /* 返回栈顶元素 */ 28 Status GetTop (SqStack S , SElemType &e ) 29 { 30 if(S.top == S.base) return ERROR;//栈空 top == base 31 e = *(S.top-1); //top指向的是栈顶元素的下一个位置 32 return OK; 33 } 34 35 /* 压栈(插入元素) */ 36 Status Push (SqStack &S , SElemType e ) 37 { 38 if(S.top - S.base >= S.stacksize)//栈满 39 { //当前存储空间已满,增加分配 40 S.base = (SElemType *)realloc(S.base, 41 (S.stacksize+STACKINCREMENT)*sizeof (SElemType)); 42 if (!S.base) exit(OVERFLOW);// 存储分配失败 43 S.top = S.base + S.stacksize;//更新栈顶 44 S.stacksize+= STACKINCREMENT; //增加存储容量 45 } 46 *S.top++ = e;//压栈并更新栈顶 47 return OK; 48 } 49 50 /* 出栈(删除栈顶元素) */ 51 Status Pop (SqStack &S , SElemType &e ) 52 { 53 if(S.top == S.base) return ERROR;//栈空 top == base 54 e = *--S.top; //更新栈顶并出栈 55 return OK; 56 } 57 58 /* 测试 */ 59 int main() 60 { 61 SqStack S; 62 SElemType e; 63 InitStack(S);//构造空栈 64 for(int i=0; i<10; ++i) 65 Push(S,i); //压栈 66 while(Pop(S,e)) 67 printf("%d\n",e);//出栈 68 return 0; 69 }
1 //浙大数据结构 \ 顺序栈 2 typedef int Position; 3 struct SNode { 4 ElementType *Data; /* 存储元素的数组 */ 5 Position Top; /* 栈顶指针 */ 6 int MaxSize; /* 堆栈最大容量 */ 7 }; 8 typedef struct SNode *Stack; 9 10 Stack CreateStack( int MaxSize ) 11 { 12 Stack S = (Stack)malloc(sizeof(struct SNode)); 13 S->Data = (ElementType *)malloc(MaxSize * sizeof(ElementType)); 14 S->Top = -1; 15 S->MaxSize = MaxSize; 16 return S; 17 } 18 19 bool IsFull( Stack S ) 20 { 21 return (S->Top == S->MaxSize-1); 22 } 23 24 bool Push( Stack S, ElementType X ) 25 { 26 if ( IsFull(S) ) { 27 printf("堆栈满"); 28 return false; 29 } 30 else { 31 S->Data[++(S->Top)] = X; 32 return true; 33 } 34 } 35 36 bool IsEmpty( Stack S ) 37 { 38 return (S->Top == -1); 39 } 40 41 ElementType Pop( Stack S ) 42 { 43 if ( IsEmpty(S) ) { 44 printf("堆栈空"); 45 return ERROR; /* ERROR是ElementType的特殊值,标志错误 */ 46 } 47 else 48 return ( S->Data[(S->Top)--] ); 49 }
二、链表栈
1 #include <stdio.h> 2 #include <malloc.h> 3 #define OK 1 4 #define ERROR 0 5 /* 0.定义结点 */ 6 typedef int SElemType, Status; 7 typedef struct stack* STACKPTR; 8 typedef struct stack STACK; 9 struct stack{ 10 SElemType e; 11 STACKPTR next; 12 }; 13 14 /* 1.push */ 15 Status push(STACKPTR *top,SElemType e) 16 { 17 STACKPTR p; 18 p = (STACKPTR)malloc(sizeof(STACK)); 19 if(p == NULL) 20 return ERROR; 21 22 p->e=e; 23 p->next = *top; 24 25 *top = p; 26 return OK; 27 } 28 29 /* 2.pop */ 30 Status pop(STACKPTR *top,SElemType *e) 31 { 32 if(*top == NULL) 33 return ERROR; 34 35 *e = (*top)->e; 36 37 STACKPTR t = *top; 38 *top = (*top)->next; 39 free(t); 40 return OK; 41 } 42 43 /* 测试代码 */ 44 int main() 45 { 46 STACKPTR top = NULL; 47 SElemType e; 48 for(int i=0; i<10; ++i) 49 push(&top,i); 50 while(pop(&top,&e)) 51 printf("%d\n",e); 52 return 0; 53 }
1 //浙大数据结构 \ 链栈 2 typedef struct SNode *PtrToSNode; 3 struct SNode { 4 ElementType Data; 5 PtrToSNode Next; 6 }; 7 typedef PtrToSNode Stack; 8 9 Stack CreateStack( ) 10 { /* 构建一个堆栈的头结点,返回该结点指针 */ 11 Stack S; 12 13 S = (Stack)malloc(sizeof(struct SNode)); 14 S->Next = NULL; 15 return S; 16 } 17 18 bool IsEmpty ( Stack S ) 19 { /* 判断堆栈S是否为空,若是返回true;否则返回false */ 20 return ( S->Next == NULL ); 21 } 22 23 bool Push( Stack S, ElementType X ) 24 { /* 将元素X压入堆栈S */ 25 PtrToSNode TmpCell; 26 27 TmpCell = (PtrToSNode)malloc(sizeof(struct SNode)); 28 TmpCell->Data = X; 29 TmpCell->Next = S->Next; 30 S->Next = TmpCell; 31 return true; 32 } 33 34 ElementType Pop( Stack S ) 35 { /* 删除并返回堆栈S的栈顶元素 */ 36 PtrToSNode FirstCell; 37 ElementType TopElem; 38 39 if( IsEmpty(S) ) { 40 printf("堆栈空"); 41 return ERROR; 42 } 43 else { 44 FirstCell = S->Next; 45 TopElem = FirstCell->Data; 46 S->Next = FirstCell->Next; 47 free(FirstCell); 48 return TopElem; 49 } 50 }
三、栈的应用举例
1、进制转换
十进制数N和其它d进制数的转换的算法基于原理: N = (N div d)×d + N mod d, 其中,div 相除取整,mod 相除取余。
计算过程是从低位到高位顺序产生d进制数的各个数位,而打印输出,一般来说应从高位到低位进行,恰好和计算过程相反。因此,若将计算过程中得到的d进制数 的各位顺序进栈,则按出栈序列打印输出的即为与输入对应 的d进制数。
/* 用上面链表栈代码测试 */ STACKPTR top = NULL; SElemType e; int n = 1348;//10进制数 int d = 8; //8进制 while(n) { push(&top,n%d); n /= d; } while(pop(&top,&e)) printf("%d",e);
2、判断进出栈顺序
1 #include <stdio.h> 2 3 void fun(const char *s){ //"CBADE" 4 const char* order = "ABCDE"; //入栈顺序 5 6 char stack[128]; //栈 7 int top = -1; //栈顶 8 9 //字符串没有比较完毕且还有字符没有进栈或者所有字符均进栈但栈不空且栈顶字符相符 10 while(*s&&(*order||top>=0&&stack[top]==*s)){ //比较字符串s 11 12 if(top==-1 || stack[top]!=*s){ //栈为空或栈顶元素与比较字符不同 13 stack[++top] = *order++; //按入栈顺序入栈并打印 I 14 printf("I"); 15 } 16 else { 17 top--; //出栈并打印 O 18 printf("O"); 19 s++; //比较下一个字符 20 } 21 } 22 if(*s) printf("\nNo!\n"); //非栈的正确进出栈顺序 23 } 24 25 int main() 26 { 27 char s[128] = "ACBED";//"CBADE"; 28 fun(s); 29 return 0; 30 }