一、概述:
栈(stack)是限制插入和删除只能在一个位置上进行的表,该位置是表的末端,叫做栈的顶(top)。对栈的基本操作有Push(进栈)和Pop(出栈),前者相当于插入,后者则是删除最后插入的元素。
栈有时又叫做LIFO(后进先出)表。在图1中描述的模型只象征着Push是输入操作而Pop和Top是输出操作。
图1 栈模型:通过Push向栈输入,通过Pop从栈输出
二、实现
1. 栈的链表实现
文件名:stack_list.h
- #ifndef _STACK_LIST_H
- #define _STACK_LIST_H
- #define ElementType int
- struct Node;
- typedef struct Node *PtrToNode;
- typedef PtrToNode Stack;
- int IsEmpty( Stack S );
- Stack CreateStack( void );
- void DisposeStack( Stack S );
- void MakeEmpty( Stack S );
- void Push( ElementType X, Stack S );
- ElementType Top( Stack S );
- void Pop( Stack S );
- #endif /* _STACK_LIST_H */
- #include "stack_list.h"
- #include "fatal.h"
- struct Node
- {
- ElementType Element;
- PtrToNode Next;
- };
- int
- IsEmpty( Stack S )
- {
- return S->Next == NULL;
- }
- Stack
- CreateStack( void )
- {
- Stack S;
- S = malloc( sizeof( struct Node ) );
- if( S == NULL )
- FatalError( "Out of space!!!" );
- S->Next = NULL;
- MakeEmpty( S );
- return S;
- }
- void
- MakeEmpty( Stack S )
- {
- if( S == NULL )
- Error( "Must use CreateStack first" );
- else
- while( !IsEmpty( S ) )
- Pop( S );
- }
- void
- Push( ElementType X, Stack S )
- {
- PtrToNode TmpCell;
- TmpCell = malloc( sizeof( struct Node ) );
- if( TmpCell == NULL )
- FatalError( "Out of space!!!" );
- else
- {
- TmpCell->Element = X;
- TmpCell->Next = S->Next;
- S->Next = TmpCell;
- }
- }
- ElementType
- Top( Stack S )
- {
- if( !IsEmpty( S ) )
- return S->Next->Element;
- Error( "Empty stack" );
- return 0;
- }
- void
- Pop(Stack S )
- {
- PtrToNode FirstCell;
- if( IsEmpty( S ) )
- Error( "Empty Stack" );
- else
- {
- FirstCell = S->Next;
- S->Next = S->Next->Next;
- free( FirstCell );
- }
- }
- #include <stdio.h>
- #include "stack_list.h"
- int main()
- {
- Stack S;
- int n, num, m;
- int i;
- S = CreateStack();
- printf( "Initialization complete.\n" );
- printf( "Please input the number of elements in the stack:\n" );
- scanf( "%d", &n );
- printf( "Please input %d elements push into stack:\n", n );
- for(i = 0; i < n; i++ )
- {
- scanf( "%d", &num );
- Push( num, S );
- }
- printf( "Please input the numbers you want pop out from the stack(no more than:%d)\n", n );
- scanf( "%d", &n );
- printf( "Pop out from the stack %d elements in turns:\n", n );
- for( i = 0; i < n; i++ )
- {
- m = Top( S );
- Pop( S );
- printf( "%3d",m );
- }
- printf( "\n" );
- return 0;
- }
2. 栈的数组实现
文件名:stack_array.h
- #ifndef _STACK_ARRARY_H
- #define _STACK_ARRARY_H
- struct StackRecord;
- typedef struct StackRecord *Stack;
- #define ElementType int
- int IsEmpty( Stack S );
- int IsFull( Stack S );
- Stack CreateStack( int MaxElements );
- void DisposeStack( Stack S );
- void MakeEmpty( Stack S );
- void Push( ElementType X, Stack S );
- ElementType Top( Stack S );
- void Pop( Stack S );
- ElementType TopAndPop( Stack S );
- #endif /* _STACK_ARRARY_H */
文件名:stack_array.c
- #include "stack_array.h"
- #include "fatal.h"
- #define EmptyTOS ( -1 )
- #define MinStackSize ( 5 )
- struct StackRecord
- {
- int Capacity;
- int TopOfStack;
- ElementType *Array;
- };
- Stack
- CreateStack( int MaxElements )
- {
- Stack S;
- if( MaxElements < MinStackSize )
- Error( "Stack size is too small" );
- S = malloc( sizeof( struct StackRecord ) );
- if( S == NULL )
- FatalError( "Out of space!!!" );
- S->Array = malloc( sizeof( ElementType ) * MaxElements );
- if( S->Array == NULL )
- FatalError( "Out of space!!!" );
- S->Capacity = MaxElements;
- MakeEmpty( S );
- return S;
- }
- void
- DisposeStack( Stack S )
- {
- if( S != NULL )
- {
- free( S-> Array );
- free( S );
- }
- }
- int
- IsEmpty( Stack S )
- {
- return S->TopOfStack == EmptyTOS;
- }
- void
- MakeEmpty( Stack S )
- {
- S->TopOfStack = EmptyTOS;
- }
- void
- Push( ElementType X, Stack S )
- {
- if( IsFull( S ) )
- Error( "Full Stack" );
- else
- S->Array[ ++S->TopOfStack ] = X;
- }
- int
- IsFull( Stack S )
- {
- return S->TopOfStack == S->Capacity - 1;
- }
- ElementType
- Top( Stack S )
- {
- if( !IsEmpty( S ) )
- return S->Array[ S->TopOfStack ];
- Error( "Empty Stack" );
- return 0; /* Return value used to avoid
- * warning */
- }
- void
- Pop( Stack S )
- {
- if( IsEmpty( S ) )
- Error( "Empty Stack" );
- else
- S->TopOfStack--;
- }
- ElementType
- TopAndPop( Stack S )
- {
- if( !IsEmpty( S ) )
- return S->Array[ S->TopOfStack-- ];
- Error( "Empty Stack" );
- return 0; /* Return value used to avoid
- * warning */
- }
文件名:main.c
- #include <stdio.h>
- #include "stack_array.h"
- #include "fatal.h"
- int main()
- {
- Stack S;
- int n, num, m;
- int i;
- S = CreateStack( 10 );
- printf( "Initialization complete.\n" );
- printf( "Please input the number of elements in the stack:\n" );
- scanf( "%d", &n );
- printf( "Please input %d elements push into stack:\n", n );
- for( i = 0; i < n; i++ )
- {
- scanf( "%d", &num );
- Push( num, S );
- }
- printf( "Top of the stack:%d\n", Top( S ) );
- printf( "Please input the numbers you want pop out from the stack(no more than %d):\n", n );
- scanf( "%d", &n );
- printf( "Pop out from the stack %d elements in turns:\n", n );
- for( i = 0; i < n; i++ )
- {
- m = TopAndPop( S );
- printf( "%3d", m );
- }
- printf( "\n" );
- return 0;
- }
附录:上述代码中用到了Error、FatalError等函数,其实现如下(即fatal.h文件):
- #include <stdio.h>
- #include <stdlib.h>
- #define Error( Str ) FatalError( Str )
- #define FatalError( Str ) fprintf( stderr, "%s\n", Str ), exit( 1 )
三、应用
1. 平衡符号:
编译器检查你的程序的语法错误,但是常常由于缺少一个符号(如遗漏一个花括号或是注释起始符)引起编译器列出上百行的诊断,而真正的错误并没有找出。
在这种情况下,一个有用的工具就是检验是否每件事情都能成对出现的一个程序。于是,每一个右花括号、右方括号及右圆括号必然对应其相应的左括号。序列“[()]”是合法的,但“[(])”是错误的。显然,不值得为此编写一个大型程序,事实上检验这些事情是很容易的。为简单起见,我们就圆括号、方括号和花括号进行检验并忽略出现的任何其他字符。
这个简单的算法用到一个栈,叙述如下:
做一个空栈。读入字符直到文件尾。如果字符是一个开放符号,则将其推入栈中。如果字符是一个封闭符号,则当栈空时报错。否则,将栈元素弹出。如果弹出的符号不是对应的开放符号,则报错。在文件尾,如果栈非空则报错。
算法实现:
- bool
- balance( char ch, Stack S )
- {
- switch( ch ) {
- case '(':
- case '[':
- case '{':
- Push( ch, S );
- break;
- case ')':
- if( IsEmpty( S ) || Top( S ) != '(' )
- {
- return false;
- }
- Pop( S );
- break;
- case ']':
- if( IsEmpty(S) || Top(S) != '[' )
- {
- return false;
- }
- Pop( S );
- break;
- case '}':
- if( IsEmpty( S ) || Top( S ) != '{' )
- {
- return false;
- }
- Pop( S );
- break;
- default:
- break;
- }
- return true;
- }
2. 后缀表达式
附录:上述代码中用到了Error、FatalError等函数,其实现如下(即fatal.h文件):
- #include <stdio.h>
- #include <stdlib.h>
- #define Error( Str ) FatalError( Str )
- #define FatalError( Str ) fprintf( stderr, "%s\n", Str ), exit( 1 )