当时我在学习数据结构栈和队列时做的最多的算法就是括号匹配问题,该算法将栈的特性淋漓尽致地体现了出来,可以称得上是一个经典程序,本文将详细分析该程序
一、栈:
首先,做这个算法之前我们应该先对栈有所了解。
栈(stack)是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
说到底,栈的基本算法思想就是“先进后出,后进先出”。
二、栈的基本操作:
设定return 0 为false,1为true
1、压栈:
// 压栈
int Push(SeqStack &L, int e)
{ // 栈已满
if(L.top==MaxSize -1)
{
return 0;
}
// 加入栈中
L.Data[L.top++] = e;
// 返回自身
return e;
}
2、弹栈:
// 弹栈
int Pop(SeqStack &L)
{ // 栈空
if(L.topIdx == 0)
{
//返回失败
return 0;
}
// 打印并返回栈
int value = L.Data[--L.top];
printf("%d ",value);
return value;
}
3、判断栈空:
//判断栈s是否为空
int Empty(SeqStack s)
{
// 如果下标在0,说明栈中无元素
if(s.top != 0)
{
return 1;
}
return 0;
}
4、判断栈满:
// 判断栈是否已栈.
Status Full(SeqStack s)
{
// 已满返回true(1)
if(s.top != MaxSize -1)//之前的定义数组的最大值的下标
{
return 1;
}
return 0;
}
三、括号匹配问题:
原题:
给定一个字符串,其中的字符只包含三种括号:尖括号<>、中括号[ ]、圆括号( ),即它仅由 “( ) [ ] <>” 这六个字符组成。设计算法,判断该字符串是否有效,即字符串中括号是否匹配。括号匹配要求括号必须以正确的顺序配对
算法实现流程图:
四、算法源代码奉上
(附有保姆级注释,供初学者参考)
#include <stdio.h>
#include <stdlib.h>
#define STACK_INIT_SIZE 20
#define STACKINCREMENT 10
typedef char 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 ) //为该栈申请空间,以s->base指向首地址,如果该指针不存在,意味着申请失败
exit(0); //直接退出(exit(0)为正常退出,exit(1)为异常退出)
s->top = s->base; //确保栈顶指针与栈尾指针指向同一个地方,即空栈
s->stackSize = STACK_INIT_SIZE;
} //申请成功,栈的空间大小为STACK_INIT_SIZE
Push(sqStack *s, ElemType e) //压栈(元素进栈)
{
if( s->top - s->base >= s->stackSize )//当栈顶指针减去栈底指针大于等于栈的容量时
{ //使用realloc追加更大空间
s->base = (ElemType *)realloc(s->base, (s->stackSize + STACKINCREMENT) * sizeof(ElemType));
if( !s->base ) //如果栈底指针不存在,申请新内存失败
exit(0); //直接退出
s->top = s->base + s->stackSize; //分配成功,栈顶指针等于栈尾指针加上栈的大小
s->stackSize = s->stackSize + STACKINCREMENT;//栈的大小等于栈的原始大小加上追加的空间
}
*(s->top) = e; // 存放数据等于e
s->top++; //栈顶指针上移一个
}
Pop(sqStack *s, ElemType *e) //弹栈(出栈操作)
{
if( s->top == s->base ) //如果栈顶指针等于栈尾指针,说明栈空,即不用继续弹栈
return 1; //返回真
*e = *--(s->top); // 将栈顶元素弹出并修改栈顶指针
}
int StackLen(sqStack s) //栈的长度
{
return (s.top - s.base); //返回值为栈顶指针减去栈底指针
}
int match(char e, char c) //定义match配对函数(返回值为int类型)
{
if( e=='(' && c==')' )
return 1;
if( e=='[' && c==']' )
return 1;
if( e=='<' && c=='>' )
return 1;
if( e=='{' && c=='}' )
return 1;
if( e=='\'' && c=='\'' )
return 1;
if( e=='"' && c=='"' )
return 1;
return 0;
}
int main() //进入主函数
{
sqStack s; //调用创建好的栈
char c, e; //定义左‘e’右‘c’
InitStack( &s ); //初始化栈
printf("请输入一系列字符串,以#作为结束标志:");
scanf("%c", &c); //输入字符
while( c != '#' )
{
if( c=='(' || c==')' || c=='[' || c==']' || c=='<' || c=='>'|| c=='{' || c=='}' )
{ // 如果是括号,就压栈
if( !StackLen(s) ) //如果栈的长度为空,即c为第一个入栈的元素,直接进栈
{
Push(&s, c); //压栈,存入c
}
else //如果c放入时栈已经不空了,
{
Pop(&s, &e);
//取出栈顶元素来判断与新放入的c是否匹配
if( !match(e, c) )
//如果match执行结果为假,即不匹配
{
Push(&s, e);
//原栈顶元素重新入栈
Push(&s, c);
//将输入的括号字符入栈
}
}
}
scanf("%c", &c);
// 输入下一个字符
}
if( !StackLen(s) )
//如果栈s为空,即所有右括号都已被匹配走
{
printf("\n输入字符串中的括号完全匹配!\n");
}
else
//如果栈s不为空,即内部还有剩余括号
{
printf("\n输入字符串中的括号不完全匹配!\n");
}
return 0;
}