(一)栈的定义及基本运算
(1)栈的定义
栈是只能通过访问它的一端来实现数据存储和检索的一种线性数据结构。换句话说,栈的修改是按先进后出的原则进行的。因此,栈又称为先进后出(FILO)的线性表。在栈中进行插入和删除操作的一端称为栈顶(top),相应地,另一端称为栈底(bottom)。不含数据元素的栈称为空栈。
(2)栈的基本算法
- 初始化栈InitStack(S):创建一个空栈S。
- 判断空栈StackEmpty(S):当栈为空栈时返回“真”,否则返回“假”。
- 入栈Push(S,x):将元素x加入栈顶,并更新栈顶指针。
- 出栈Pop(S):将栈顶的元素从栈中删除,并且更新栈顶指针。
- 读栈顶元素Top(S):返回栈顶元素的值,但不修改栈顶的指针。
(二)栈的存储结构
(1)栈的顺序存储。
栈的顺序存储是指用一组地址连续的存储单元依次存储自栈顶到栈底的数据元素,同时附设指针top指示栈顶元素的位置。采用顺序存储结构的栈也称为顺序栈。在顺序存储方式下,需要预先定义或申请栈的存储空间,也就是说栈空间的容量是有限的。因此在顺序栈中,当一个元素入栈时,需要判断是否栈满(即栈空间中没有空闲单元),若栈满,则元素入栈会发生上溢现象。
(2)栈的链式存储。
为了克服顺序存储的栈可以存在上溢的不足,可以用链表存储栈中的元素。用链表作为存储结构的栈也称为链栈。由于栈中元素的插入和删除仅在栈顶一端进行,因此不必另外设置头指针,链表的头指针就是栈顶指针。链栈表示如下图:
(三)栈的应用
栈的典型应用包括表达式求值,括号匹配等。在计算机语言的实现以及将递归过程转变为非递归过程的处理中,栈有重要的作用。
【例】表达式求值
计算机在处理算术表达式时,可将表达式先转换为后缀形式,然后利用栈进行计算。例如,表达式“46+5 *(120-37)”的后缀表达式为“46 5 120 37 - * +”。计算后缀表达式时,从左至右扫描表达式:若遇到运算对象,则压入栈中;遇到运算符,则从栈顶弹出运算对象进行计算,并将运算结果压入栈中。重复以上过程,直到后缀表达式扫描结束。例如“46 5 120 37 - * +”的计算过程为:
1、依次将46,5,120,37压入栈中;
2、遇到“-”取37,120,计算120-37,得83,将其压入栈中;
3、遇到“*”取出83,5,计算83*5,得415,将其压入栈中;
4、遇到“+”,取出415,46,计算46+415,得461,将其压入栈中;
5、表达式结束,计算过程完成。
下面函数computing(char expr[],int *result)的功能是基于栈计算后缀形式的表达式(以串形式存入字符数组expr)的值,并通过参数result带回该值。函数的返回值为-1/0,分别表示表达时有/无错误。假设表达式中仅包含数字,空格和算术运算符号,其中所有项均以空格分隔,且运算符仅包含(“+”),(“-”),(“*”),(“\”)。
void InitStack(STACK *s):初始化栈。
void Push(STACK *s, int e):将一个整数压入栈,栈中元素数目增加1。
void Pop(STACK *s);栈顶元素出栈,栈中元素数目减1。
int Top(STACK s):返回非空栈的栈顶元素值,栈中元素不变。
int IsEmpty(STACK s);若s是空 栈,则返回1;否则返回0。
【函数】
int computing (char expr[], int * result)
{
STACK s; int tnum,a,b; char *ptr;
InitStack(&s);
ptr = expr; /*字符指针指向后缀表达式串的第一个字符*/
while (*ptr != '\0')
{
if ( *ptr == ' ') /*当前字符是空格,则取下一个字符*/
{
ptr++;
continue;
}
else if ( isdigit(*ptr)) /*当前字符是数字,则将数字串转化为数值*/
{
tmun = 0;
while(*ptr >= '0' && *ptr <= '9')
{
tnum = tnum *10 + *ptr - '0';
ptr++;
}
Push(&s,tnum);
}
else if ( *ptr == '+' || *ptr == '-' || *ptr == '*' || *ptr == '/') /*当前是运算符*/
{
if ( !IsEmpty(s)){
a = Top(s);Pop(&s); /*取运算符的第二个运算符,存入a*/
if ( IsEmpty(s)) {
b = Top(s); Pop(&s); /*取运算符的第一个运算符,存入b*/
}
else
{
return -1;
}
}
else
{
retun -1; /*栈空*/
}
switch ( *ptr) {
case '+' : Push(&s,b+a);break;
case '-': Push(&s,b-a);break;
case '*': Push(&s,b*a);break;
case '/': Push(&s,b/a);break;
}
}
else /*非法字符*/
{
return -1;
}
ptr++;
}/*while*/
if (IsEmpty(s))
return -1;
else
{
*result = Top(s);Pop(&s); /*得到运算结果*/
if (!IsEmpty(s)
return -1;
retrun 0;
}
}
下一期我来讲用两个队列使用栈,使用两个栈来使用队列!