链栈
栈属于一种操作受限的线性表,自然也有顺序和链式之分,采用链式存储结构存储的栈称之为链栈,在前面学习链表时,介绍过头插法建表的方法,当时特别强调表的顺序和原序列相反。正好符合栈后进先出的特性。下面的链式存储结构即为采用头插法建立的链表
-
栈空条件:
s->next == NULL
-
栈满条件:由于采用链式存储结构,不考虑
-
入栈:将新元素插到头结点后面
-
出栈:取出头结点之后的结点并删除之
链栈的存储结构
typedef struct _linkStack{
ElemType data;
struct _linkStack *next;
}linkStack;
链栈的基本运算
链栈的基本运算和单链表一致,不需要单独掌握
初始化
void
initStack( linkStack **s )
{
*s = ( linkStack* )malloc( sizeof( linkStack ) );
(*s)->next = NULL;
}
销毁
void
destroyStack( linkStack *s )
{
linkStack *t;
for( s; s != NULL; s = t ){
t = s->next;
free( s );
}
}
判断是否为空
int
stackEmpty( linkStack *s )
{
return ( s->next == NULL );
}
入栈
void
push( linkStack *s, char e )
{
linkStack *t;
t = ( linkStack* )malloc( sizeof( linkStack ) );
t->data = e;
t->next = s->next;
s->next = t;
}
出栈
int
pop( linkStack *s, char *e )
{
linkStack *t;
if( s->next == NULL ){
return FALSE;
}
t = s->next;
*e = t->data;
s->next = t->next;
free( t );
return TRUE;
}
取得栈顶元素
int
getTop( linkStack *s, char *e )
{
if( s->next == NULL ){
return FALSE;
}
*e = s->next->data;
return TRUE;
}
栈的应用:判断表达式的括号是否配对
给定一个只有小括号的表达式,要求设计算法判断左右括号是否配对
基本的思路是遇见左括号就进栈,遇见右括号就出栈
- 若遍历完表达式后栈不为空,则说明表达式有多余的左括号
- 若程序试图对空栈执行出栈操作说明有多余的右括号
- 当遍历完表达式后栈为空,且没有尝试过对空栈执行出栈操作,则说明表达式左右括号配对
int i;
char e;
int right = TRUE;
char str[] = "(((( 3 * ( 1 + 2 ) )))";
linkStack *s;
initStack( &s );
for( i = 0; str[i] != '\0'; i++ ){
if( str[i] == '(' ){
push( s, str[i] );
}else if( str[i] == ')' ){
if( pop( s, &e ) == FALSE ){
right = FALSE;
break;
}
}
}
if( stackEmpty( s ) && right ){
printf("Pass");
}else{
if( right ){
printf("Error : 多余的左括号\n");
}else{
printf("Error : 多余的右括号\n");
}
}
destroyStack( s );