堆栈的介绍
栈是一种特殊的线性表,特点是:是一种后进先出的线性表,只能在栈顶对数据进行插入,删除和取元素等操作。一种比较形象的记忆法是假如你面前有一摞盘子,而最方便和约定俗成的方法是取最上面的盘子,添加盘子时也是把它放在最上面,而对于栈来说是必须要这么做的。
用数组实现的一个简单的栈 SeqStack.h
//顺序栈的操作实现
#include"stdio.h"
#include"stdlib.h"
#define MaxStackSize 20
typedef char DataType;
//结点的定义
typedef struct
{
DataType stack[MaxStackSize];
int top;
}SeqStack;
//操作的定义
void Initiate(SeqStack *s)
{
s->top=0;
}
int StackEmpty(SeqStack *s)
{
if(s->top>0)
return 1;
else
return 0;
}
//入栈
int StackPush(SeqStack *s,DataType x)
{
if(s->top<MaxStackSize)
{
s->stack[s->top]=x;
s->top++;
return 1;
}
else
return 0;
}
//出栈
void StackPop(SeqStack *s,DataType *x)
{
if(s->top>0)
{ s->top--;
*x=s->stack[s->top];
}
else
{
printf("栈为空\n");
}
}
void StackTop(SeqStack *s,DataType *d)
{
if(s->top>0)
{
*d=s->stack[s->top-1];
}
else
{
printf("栈为空\n");
}
}
栈的应用 之一 进行括号匹配
这里的括号所举的例子是圆括号,中括号和花括号。
算法描述:顺序扫描要判断的字符串,当遇到左括号时,将字符串入栈。当扫描到右括号时,比较当前栈顶的括号和扫描到的右括号是否匹配,如匹配,将此时栈顶的元素退栈,继续扫描字符串,若当前的元素和栈顶的元素不匹配时,则匹配次序不成功,若字符串为某种类型的右括号,而栈已空,则说明,右括号多于左括号匹配不成功,若扫描结束后,栈不为空,则说明左括号多于右括号,匹配不成功。否则,匹配成功。
功能函数 int MatBrackets(char *a,int n)
int MatchBrackets(char *a,int n)
{
//扫描字符串,将其中的左括号入栈
SeqStack s;
int i,j;
char k;
Initiate(&s);
for(i=0;i<n;i++)
{
if(a[i]=='('||a[i]=='['||a[i]=='{')
{
//将其入栈
StackPush(&s,a[i]);
}
else if(!(a[i]>='a'&&a[i]<='z'))
{
if(StackEmpty(&s))//判断栈是否为空 非空为1
{
StackTop(&s,&k);//取一下也是可以的
// printf("%c\n",k);
}
else
{
printf("右括号多于左括号,不匹配\n");
return 0;
}
if(a[i]==')')
{
if(k=='(')
StackPop(&s,&k); //出栈
else
{
printf("括号次序不匹配\n");
return 0;
}
}
if(a[i]=='}')
{
if(k=='{')
StackPop(&s,&k); //出栈
else
{
printf("括号次序不匹配\n");
return 0;
}
}
if(a[i]==']')
{
if(k=='[')
StackPop(&s,&k); //出栈
else
{
printf("括号次序不匹配\n");
return 0;
}
}
}
}
//当遍历完了之后,出现的情况 有出现一些括号,然后栈为空。
if(StackEmpty(&s))
{
printf("左括号多于右括号,不匹配\n");
}
else
{ printf("括号匹配正确\n");
return 1;
}
}
将中缀表达式转换为后缀表达式
表达式的组成,分为操作数,运算符和分界符。例如表达式A+(B-C/D)*E中,A,B,C,D,E是操作数,+-/*是运算符,()括号是分界符,将之变为后缀表达式的结果是ABCD/-E*+,
将中缀表达式转化为后缀表达式的算法是:
(1)初始化一个堆栈,初始化时将栈顶的元素置为#
(2)顺序读入中缀表达式,当读到操作数时,将其作为后缀表达式的一部分进行输出
(3)当读到运算符时,取出栈顶的元素a,此时扫描到的元素为b,比较a和b之间的优先级,若a的优先级要高于b的优先级,则将a出栈,作为后缀表达式的一部分进行输出,再取出栈顶的元素,与b进行比较,若新的栈顶元素a的还是大于b的优先级,则与上一步操作一样,若a的优先级要低于b的优先级,则将b进行入栈,在去读取字符串的下一个元素,若a的优先级等于b的优先级且a为(,b为),此时仅仅将a进行出栈操作,读取下一个元素,若a的优先级等于b的优先级,a为#,b为#,转换完成。
int Compare(char a1,char a2)
{
if((a1=='+'||a1=='-')&&(a2=='+'||a2=='-'||a2==')'||a2=='#'))
return 1;
else if(a1=='+'||a1=='-')
return -1;
if((a1=='*'||a1=='/')&&(a2=='('))
return -1;
else if(a1=='*'||a1=='/')
return 1;
if(a1=='('&&a2!=')')
return -1;
else if(a1=='('&&a2==')')
return 0;
if(a1==')'&&a1!='(')
return 1;
if(a1=='#'&&a2=='#')
return 0;
else if(a1=='#'&&a2!=')')
return -1;
}
char* PostExp(char *a,int n)
{
char *b;
int i,j,m;
char k;
SeqStack s;
b=(char*)malloc(sizeof(char )*n);
j=0;
i=0;
Initiate(&s);
StackPush(&s,'#');//将#进行进栈
//第一遍遍历的之后将所有的数字先输出来
for(;i<n;i++)
{
if(a[i]>='0'&&a[i]<='9')
{
b[j]=a[i];
j++;
}
else
{
StackTop(&s,&k);
m=Compare(k,a[i]);//比较栈顶元素和当前扫描到的元素
printf("扫描到的元素%c\n",a[i]);
printf("栈顶的元素%c\n",k);
if(m>0)// 栈顶的优先级要高于当前扫描到的优先级
{
while(StackEmpty(&s)&&m>0)
{
b[j]=k;
j++;
StackPop(&s,&k);
StackTop(&s,&k);
m=Compare(k,a[i]);
}
}
if(m<0)
{
StackPush(&s,a[i]);
}
if(m==0&&k=='('&&a[i]==')')
{
StackPop(&s,&k);
}
if(m==0&&a[i]=='#'&&k=='#')
{
printf("算法结束\n");
}
}
}
b[j]='\0';
for(i=0;b[i]!='\0';i++)
printf("%c ",b[i]);
return b;
}
//用于测试的主函数 test.c
void main()
{
char a[]="(())abc{[][[]()}";
char b[]="(()))abc{[]}";
char c[]="(()()abc{[]}";
char d[]="(())abc{([]}";
char e[]="3+(4-4/2)*7#";
char g[]="(1+2)*3-(4-5)*6-7#";
char *f;
int i;
int n1=strlen(a);
int n2=strlen(b);
int n3=strlen(c);
int n4=strlen(d);
int n5=strlen(g);
int n6=strlen(e);
MatchBrackets(a,n1);
MatchBrackets(b,n2);
MatchBrackets(c,n3);
MatchBrackets(d,n4);
f=PostExp(g,n5);
f=PostExp(e,n6);
}
以上是我学习数据结构的一些笔记,大部分是按照数据结构(朱战立版)书上的描述,自己去动手实现的。写下来,与大家一起学习,同时自己也便于自己以后参考。