数据结构 - 栈
栈是限定仅在表尾进行插入和删除操作的线性表(函数调用过程,列车进入车站)
一、栈的定义(先进后出,后进先出)
栈顶(top): 允许插入和删除
栈底(bottom):最先进来的元素将会留在栈底

栈的ADT
数据对象:D = {ai | ai 属于 ElemSet, i = 1, 2, 3, 4... n , n >= 0}
数据关系:同线性表,元素具有相同的类型,相邻元素具有前驱与后继关系。
操作:
- InitStack(*S):初始化操作,建立一个空栈S.
- DestoryStack(*S): 若栈存在,则销毁它。
- ClearStack(*S): 将栈清空
- StackEmpty(S): 若栈为空,返回true, 否则返回false.
- StackLength(S): 返回栈S的元素个数。
- GetTop(S, *e): 若栈存在且非空,用e返回S的栈顶元素
- Push(*S, e): 若栈S存在,插入新元素e到栈S中并成为栈顶元素
- Pop(*S, *e): 删除栈S中栈顶元素,并用e返回其值。
- StackTraverse(S, visit()): 从栈底到栈顶依次对S的每个数据元素调用函数visit()。
二、栈的顺序存储结构及实现
栈的结构定义
/* stack.h栈的顺序存储表示 */ #define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */ #define STACKINCREMENT 2 /* 存储空间分配增量 */ typedef struct SqStack { SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */ SElemType *top; /* 栈顶指针 */ int stacksize; /* 当前已分配的存储空间,以元素为单位 */ }SqStack; /* 顺序栈 */ /* * 操作结果: 构造一个空栈S */ Status InitStack(SqStack *S); /* * 初始条件:栈S已存在 * 操作结果:栈S被销毁 */ Status DestroyStack(SqStack *S); /* * 初始条件: 栈S已存在 * 操作结果: 将S清为空栈 */ Status ClearStack(SqStack *S); /* * 初始条件:栈S已存在 * 操作结果:若栈S为空栈,则返回true, 否则返回false */ Status StackEmpty(SqStack S); /* * 初始条件: 栈S已存在 * 操作结果: 返回S的元素的个数,即栈的长度 */ int StackLength(SqStack S); /* * 初始条件: 栈S已存在且非空 * 操作结果: 用e返回S的栈顶元素 */ Status GetTop(SqStack S,SElemType *e); /* * 初始条件: 栈S已存在 * 操作结果: 返回S的元素的个数,即栈的长度 */ Status Push(SqStack *S,SElemType e); /* * 初始条件: 栈S已存在且非空 * 操作结果: 删除S的栈顶元素,并用e返回其值 */ Status Pop(SqStack *S,SElemType *e); /* * 初始条件: 栈S已存在且非空 * 操作结果: 从栈底到栈顶依次对s的每个数据元素调用函数visit() */ Status StackTraverse(SqStack S,Status(*visit)(SElemType));
顺序栈操作的实现
/* stack.c 顺序栈(存储结构由stack.h定义)的基本操作(9个) */ Status InitStack(SqStack *S) { /* 构造一个空栈S */ (*S).base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType)); if(!(*S).base) exit(OVERFLOW); /* 存储分配失败 */ (*S).top=(*S).base; (*S).stacksize=STACK_INIT_SIZE; return OK; } Status DestroyStack(SqStack *S) { /* 销毁栈S,S不再存在 */ free((*S).base); (*S).base=NULL; (*S).top=NULL; (*S).stacksize=0; return OK; } Status ClearStack(SqStack *S) { /* 把S置为空栈 */ (*S).top=(*S).base; return OK; } Status StackEmpty(SqStack S) { /* 若栈S为空栈,则返回TRUE,否则返回FALSE */ if(S.top==S.base) return TRUE; else return FALSE; } int StackLength(SqStack S) { /* 返回S的元素个数,即栈的长度 */ return S.top-S.base; } Status GetTop(SqStack S,SElemType *e) { /* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */ if(S.top>S.base) { *e=*(S.top-1); return OK; } else return ERROR; } Status Push(SqStack *S,SElemType e) { /* 插入元素e为新的栈顶元素 */ if((*S).top-(*S).base>=(*S).stacksize) /* 栈满,追加存储空间 */ { (*S).base=(SElemType *)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(SElemType)); if(!(*S).base) exit(OVERFLOW); /* 存储分配失败 */ (*S).top=(*S).base+(*S).stacksize; (*S).stacksize+=STACKINCREMENT; } *((*S).top)++=e; return OK; } Status Pop(SqStack *S,SElemType *e) { /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */ if((*S).top==(*S).base) return ERROR; *e=*--(*S).top; return OK; } Status StackTraverse(SqStack S,Status(*visit)(SElemType)) { /* 从栈底到栈顶依次对栈中每个元素调用函数visit()。 */ /* 一旦visit()失败,则操作失败 */ while(S.top>S.base) visit(*S.base++); printf("\n"); return OK; }
三、栈的链式存储结构
/* 链栈的定义 */ typedef struct StackNode { SElemType data; struct StackNode * next; } StackNode, *LinkStackPtr; typedef struct LinkStack { LinkStackPtr top; int count; } LinkStack;
栈的插入与删除
/* 栈的链式存储结构 - 入栈操作 */ /* 插入元素e为新的栈顶元素 */ Status Push(LinkStack *S, SElemType e) { LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode)); s->data = e; s->next = S->top; //把当前有栈顶指针赋值给新结点直接后继 S->top = s; //将新结点s赋值给栈顶指针 S->count++; //计数 return OK; } /* 栈的链式存储结构 - 出栈操作 */ /* 插入元素e为新的栈顶元素 */ Status Pop(LinkStack *S, SElemType *e) { LinkStackPtr p; if(StackEmpty(*S)) return ERROR; *e = S->top->data; //将栈顶元素值赋值给e p = S->top; //将栈顶点赋值给p S->top = S->top->next; //将指针下移一位 free(p); //释放内存p S->count--; return OK; }
四、栈的应用
编写一个简单的计算器程序,用来计算按照逆波兰符号(Reverse Polish Notation, PRN)录入的整数表达式。
逆波兰符号指运算符在操作数的后边。
例如: 用户输入如下表达式
30 5 - 7 *
结果为175。
程序执行步骤:
第一步:将30压入栈
第二步:将5压入栈
第三步:将5与30取出,计算30-5的值得25
第四步:将25压入栈
第五步:将7压入栈
第六步:将7与25取出,相乘得175
第七步:将175入栈
无输入,返回结果。
/* *RPN:Reverse Polish Notation *逆波兰表达式:将数据存储在栈中进行计算时,入栈时将按照以下顺序 *如:(1-2)*(4+5) RPN是: 1 2 - 4 5 + * *如: 5 -(6+7)* 8 + 9 / 4 RPN是: 5 6 7 + 8 * - 9 4 / */ #include <stdio.h> #include <ctype.h> #include <stdlib.h> #define STACK_INIT_SIZE 20 #define STACKINCREMENT 10 #define MAXBUFFER 10 /* 定义栈结构 */ typedef double ElemType; typedef struct { ElemType *base; ElemType *top; int stacksize; }sqStack; //初始化栈 InitStack(sqStack *s) { s->base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType)); if (!s->base) exit(0); s->top = s->base; s->stacksize = STACK_INIT_SIZE; } //入栈操作 Push(sqStack *s, ElemType e) { if (s->top - s->base >= s->stacksize) { s->base = (ElemType *)malloc((STACK_INIT_SIZE + STACKINCREMENT) * sizeof(ElemType)); if (!s->base) exit(0); s->top = s->base + s->stacksize; } *(s->top) = e; s->top++; } //出栈操作 Pop(sqStack *s, ElemType *e) { if (s->top == s->base) return; *e = *--(s->top); } //获取栈长度 int StackLen(sqStack s) { return (s.top - s.base); } int main() { sqStack s; char c; double d, e; char str[MAXBUFFER]; int i = 0; InitStack(&s); /* 初始化栈 */ printf("Input datas with Reverse Polish Notation,Ending with '#' \n"); scanf("%c", &c); while (c != '#') { while (isdigit(c)) //数字与空格的处理 { str[i++] = c; str[i] = '\0'; if (i >= 10) { printf("ERROR:Data is out of range \n"); return -1; } scanf("%c", &c); if (c == ' ') { d = atof(str); Push(&s, d); // 入栈 i = 0; break; } } switch (c) //四则运算符号处理 { case '+': Pop(&s, &e); Pop(&s, &d); Push(&s, d + e); break; case '-': Pop(&s, &e); Pop(&s, &d); Push(&s, d - e); break; case '*': Pop(&s, &e); Pop(&s, &d); Push(&s, d * e); break; case '/': Pop(&s, &e); Pop(&s, &d); if (e != 0) { Push(&s, d / e); } else { printf("ERROR:Input Wrong"); return -1; } break; } scanf("%c", &c); } Pop(&s, &d); printf("Result is: %f\n", d); return 0; }
问题:用两个栈实现队列
思路:定义s1,s2, 两个栈
当入队时,将数据压入s1
当出队时,将数据倒入s2, 取出第栈底元素,再将s2倒入s1

浙公网安备 33010602011771号