zoukankan      html  css  js  c++  java
  • 栈的应用

     学习数据结构一年了,现在才有点时间开始慢慢总结之前学过的一些东西,数据结构的好坏体现的 是一个程序员的基本功。数据结构和算法是一体的,当我们研究数据结构时,通常也涉及到算法。平时没有养成一个好的习惯,将很多东西都忘记了,以后努力将每天所学到的知识进行一个总结。闲话不多说。
       栈,是一种在表尾进行插入或者删除的线性表。其特点为后进先出(LIFO),存储结构分为顺序存储或者链式存储。具体的概念性的东西可以参照一下严蔚敏版数据结构。下面就谈一下栈的三个有意思的应用:括号匹配,迷宫求解,表达式求值
         括号匹配算法:

            括号匹配算法的思想非常简单,遍历输入的字符串,如果开始输入的是右括号)或者],则不能够匹配。其他情况下首先将左括号压入栈(或者[,然后在访问下一个字符,若还是左括号,继续入栈。当遇到有括号的时候,判断一下是否与前面一个符号相匹配,若匹配,则进行出栈操作。然后访问下一个符号,重复上面的操作。

    #include<iostream>
    using namespace std;
    #define ERROR 0
    #define OK 1
    #define STACK_INIT_SIZZE 100
    #define STACKINCREMENT 10
    #define SElemType char 
    
    typedef struct SqStack{
    
    	SElemType *base;//栈底指针
    	SElemType *top;//栈顶指针
    	int size;
    }SqStack;
    
    //初始化一个栈
    int InitStack( SqStack &s)
    {
    	s.base=(SElemType*)malloc(STACK_INIT_SIZZE*sizeof(SElemType));
    	if(s.base==NULL)return ERROR;
    
    	s.top=s.base;//设置栈表为空
    	s.size=STACK_INIT_SIZZE;//当前栈的长度
    	return OK;	
    }
    
    int StackEmpty(SqStack s)
    {
    	if(s.base==s.top)//当栈顶等于栈底的时候说明栈为空
    		return OK;
    	return ERROR;
    }
    
    //入栈
    int Push(SqStack &s, SElemType e)
    {
    	if(s.top-s.base>STACK_INIT_SIZZE)
    	{
    		s.base=(SElemType*)realloc(s.base,(s.size+STACKINCREMENT)*sizeof(SElemType));//如果内存满了重新分配内存空间
    		if(!s.base)exit(ERROR);//内存分配失败
    		s.top=s.base+STACK_INIT_SIZZE;
    		s.size+=STACKINCREMENT;//将容量扩大
    
    	}
    	*(s.top++)=e;
    
    	return OK;	
    }
    
    	//如果栈表不为空,则删除s的栈顶元素,并用e将其值返回回来
    int Pop(SqStack &s,SElemType &e)
    {
    	if(s.base==s.top)return ERROR;
    	e=*(--s.top);
    	return OK;
    	
    }
    
    void DestoryStack(SqStack &s)
    {
    	free(s.base);
    }
    
    int StackLength(SqStack s)
    {
    	int i=0;
    	while(s.base!=s.top)
    	{
    		i++;
    		s.top--;
    	}
    
    	return i;
    }
    
    
    //判断输入的数据是否匹配
    int Match(char s[],SqStack &l)
    {
    	printf("%s
    ",s);
    	int i,j=0;
    	int length=strlen(s);
    	char *a=new char[];
    	for(i=0;i<length;i++)
    	{
    		if(StackEmpty(l))
    		{
    			if(s[i]==')'||s[i]==']')
    				return ERROR;
    			else if(s[i]=='('||s[i]=='[')
    				Push(l,s[i]);
    		}
    		else if(!StackEmpty(l))
    		{
    			if(s[i]==')')
    				if(*(l.top-1)=='(')
    					Pop(l,a[j++]);//将该括号弹出栈
    			if(s[i]==']')
    				if(*(l.top-1)=='[')
    					Pop(l,a[j++]);
    			if(s[i]=='('||s[i]=='[')
    				Push(l,s[i]);
    		}
    	}
    	if(StackEmpty(l))
    		return OK;
    	return ERROR;
    	
    }
    
    int main()
    {
    	SqStack l;
    	char s[100];
    	scanf("%s",&s);
    	InitStack(l);
    	if(Match(s,l))
    		printf("括号是匹配的!
    ");
    	else
    		printf("括号不匹配!
    ");
    	if(l.top==l.base)
    		printf("栈已经被清空!
    ");
    	return 0;
    }
    
      迷宫求解:

        迷宫求解问题是一个经典的程序设计问题,计算机在解决此类问题的时候通常使用的穷举法,具体思想是:从入口出发,沿着某一特定的方向向前进行探索,若走得通,就继续向前走;否则原路退回,换一个方向再继续探索。直到将所有可能的路径都探索到为止。为了保证任何路径都能沿原路返回,就需要一个后进先出的结构来保存路径,所以就要用到栈。

       其描述如下:

            设置当前位置的初值为栈的入口位置;

            do{

                    若当前位置可通      //将当前位置纳入路径

                   则{

                        将当前位置进行入栈处理,并将当前位置标记下来

                        若当前位置为出口位置,则结束

                        否则将当前位置东边的邻块设置为新的当前位置

                  } 

              否则

            {

                  若栈不为空,且栈顶元素还有其他位置方向没有探索

                  则设定新的当前位置为沿顺时针方向找到栈顶位置的下一个相邻块

                  栈不为空,当时栈顶位置的四周都不通

                  {

                          删除栈顶元素

                          若栈还不为空则重新测试新的栈顶位置

                              直到找到一个可通的相邻块或者或者栈为空

                  }

           }

           }while(栈不为空)

      可通是指当前未曾走到的通道块。不然会形成循环。

    #include<iostream>
    using namespace std;
    #define Status int 
    #define OK 1
    #define ERROR 0
    #define STACK_SIZE 100
    #define INCREMENT_SIZE 10
    
    int MAZE[10][10]=
    {
    	{0,0,0,0,0,0,0,0,0,0},
    	{0,1,1,0,1,1,1,0,1,0},
    	{0,1,1,0,1,1,1,0,1,0},
    	{0,1,1,1,1,0,0,1,1,0},
    	{0,1,0,0,0,1,1,1,1,0},
    	{0,1,1,1,0,1,1,1,1,0},
    	{0,1,0,1,1,1,0,1,1,0},
    	{0,1,0,0,1,1,1,0,1,0},
    	{0,0,1,1,1,1,1,1,1,0},
    	{0,0,0,0,0,0,0,0,0,0}
    };
    
    typedef struct{
    	int x;
    	int y;
    }PosType;
    
    typedef struct{
    
    	int ord;//通道块路径上面的序号
    	PosType seat;//通道块在迷宫当中的坐标
    	int di;//从此通道块向下一通道块所走的方向;
    }SElemType;
    
    typedef struct{
    
    	SElemType *top;//栈顶元素
    	SElemType *base;//栈底元素
    	int size;	
    }SqStack;
    
    Status InitStack(SqStack &S);
    void Push(SqStack &S,SElemType e);
    void Pop(SqStack &S,SElemType &e);
    Status StackEmpty(SqStack S);
    
    //地图探索的操作
    int Pass(PosType pos);
    void FootPrint(PosType pos);
    void MarkPrint(PosType pos);
    PosType NextPos(PosType curpos,int di);
    Status MazePath(PosType start,PosType end);
    int Equals(PosType p1,PosType p2);
    
    
    int main()
    {
    	int i,j;
    	PosType start,end;
    	start.x=start.y=1;
    	end.x=end.y=8;
    
    	for(i=0;i<10;i++)
    	{
    		for(j=0;j<10;j++)
    			printf("%d ",MAZE[i][j]);
    		printf("
    ");
    	}
    
    	if(MazePath(start,end))
    		printf("该迷宫存在解
    ");
    	else
    		printf("该迷宫不存在解
    ");
    
    	for(i=0;i<10;i++)
    	{
    		for(j=0;j<10;j++)
    			printf("%d ",MAZE[i][j]);
    		printf("
    ");
    	}
    	return 0;
    }
    
    
    Status InitStack(SqStack &S)
    {
    	S.base=(SElemType*)malloc(STACK_SIZE*sizeof(SElemType));
    	if(!S.base)return ERROR;
    	S.top=S.base;
    	S.size=STACK_SIZE;
    	return OK;
    }
    
    void Push(SqStack &S,SElemType e)
    {
    	if(S.top-S.base>=STACK_SIZE)
    	{
    		S.base=(SElemType*)realloc(S.base,(S.size+INCREMENT_SIZE)*sizeof(SElemType));
    		S.top=S.base+S.size;
    		S.size+=INCREMENT_SIZE;
    	}
    	*S.top++=e;
    }
    
    void Pop(SqStack &S,SElemType &e)
    {
    	if(S.base==S.top)exit(0);
    	e=*(--S.top);
    }
    
    Status StackEmpty(SqStack S)
    {
    	if(S.base==S.top)
    		return OK;
    	else
    		return ERROR;
    }
    
    
    int Pass(PosType pos)
    {
    	if(MAZE[pos.y][pos.x]==1)
    		return OK;
    	return ERROR;
    }
    
    void FootPrint(PosType pos)//留下足迹
    {
    	MAZE[pos.y][pos.x]=2;
    }
    
    void MarkPrint(PosType pos)
    { 
    //	printf("(%d,%d)
    走不通
    ",pos.y,pos.x);
    	MAZE[pos.y][pos.x]=0;
    }
    
    PosType NextPos(PosType Curpos,int di)
    {
    	switch(di)
    	{
    	case 1:Curpos.x++;	break;//向东探索		
    	case 2:Curpos.y++;break;
    	case 3:Curpos.y--;break;	
    	case 4:Curpos.x--;break;
    	}
    	return Curpos;
    }
    
    int Equals(PosType p1,PosType p2)
    {
    	if(p1.x==p2.x&&p1.y==p2.y)
    		return OK;
    	else
    		return ERROR;
    }
    
    Status MazePath(PosType start,PosType end)
    {
    	SqStack S;
    	PosType curpos;
    	SElemType e;
    	int curstep=1;
    	curpos=start;
    	InitStack(S);
    	do{
    		if(Pass(curpos))//当前位置可通
    		{
    			FootPrint(curpos);
    			e.ord=curstep;
    			e.seat=curpos;
    			e.di=1;
    			Push(S,e);
    			if(Equals(curpos,end))return OK;
    			curpos=NextPos(curpos,1);
    			curstep++;
    		}else//如果当前位置不可通
    		{
    			if(!StackEmpty(S))
    			{
    				Pop(S,e);
    				while(e.di==4&&!StackEmpty(S))//留下不能通过的标记,并且退回一格
    				{
    					MarkPrint(e.seat);
    					Pop(S,e);
    				}
    				if(e.di<4)
    				{
    					e.di++;
    					Push(S,e);//换下一个方向进行探索
    					curpos=NextPos(e.seat,e.di);
    				}
    			}
    		}
    	}while(!StackEmpty(S));
    	return ERROR;;
    }
    
    
    
    
    
    

    表达式求值算:

           表达式求值是程序设计语言编译中一个基本的问题,他是实现栈的又一个经典的例子。通常使用的方法称作"算符优先法"

           要对表达式进行求值,首先要正确理解表达式,即要了解他的运算规则,下面以简单的加减乘除四则运算为例:

    主要有下面几条规则:

       (1)先乘除,后加减

       (2)从左算到右

       (3)先括号内后括号外

    算符的对应的优先关系有以下三中:

      a>b  a的优先权高于b

     a=b  a的优先权等于b

     a<b  a的优先权小于b

    根据上面的三种有限规则,构造下面的算符有限表

      

    由规则3可知 a为+.-.*./时的优先性低于"("但高于")",由规则2可知,当a,b为相同的算符时,a>b。"#"是表达式结束符。为了算符简洁,在表达式的最左边也虚设一个"#",使后面的算符有比较的对象,并且能够正常进入栈中。表中的"("=")"表示当左右括号相遇的时候,括号内的运算完成,然后进行去括号操作,一些算符之间没有优先关系是因为他们两两之间并不能够相邻。一旦出现相邻的情况,则认为语法错误。

          为了实现算符优先运算,可以使用两个工作栈。一个称作oprt,用以寄存运算符,另一个称作opnd,用以存储操作数或者运算结果。

          算法思想:

           (1)首先将操作数栈设置为空栈,表达式起始符"#"为运算符栈的栈底元素

            (2)一次读入表达式中的每一个字符,若是操作数,则进入操作数栈,若是运算f符,则和栈顶算符比较优先权既然后在进行相应的操作。假设a为栈顶运算符,b为读入的运算符,若若a>b,则在操作数栈中弹出两个操作数,然后将栈顶运算符弹出,进行对应的运算,再将结果压入操作数栈。若a<b,则将b压入运算符栈。若a=b则进行去括号处理。直到读入的字符为"#"或者栈顶元素为"#"

    源代码:

      

    #include<iostream>
    using namespace std;
    
    #define OK 1
    #define ERROR -1
    #define STACK_INIT_SIZE 100
    #define STACKINCREMENT 10
    #define Status int
    #define ElemType char
    #define OPSETSIZE 8
    
    typedef struct Operand{//操作数
    
    	double *base;//栈底指针
    	double *top;//栈顶指针
    	int size;
    }Operand;
    
    typedef struct Operator{
    
    	char *base;//栈底指针
    	char *top;//栈顶指针
    	int size;
    }Operator;
    
    Status InitOprd(Operand &oprd)
    {
    	oprd.base=(double*)malloc(STACK_INIT_SIZE*sizeof(double));
    	if(oprd.base==NULL)return ERROR;
    	oprd.top=oprd.base;
    	oprd.size=STACK_INIT_SIZE;
    	return OK;
    }
    
    Status InitOprt(Operator &oprt)
    {
    	oprt.base=(char*)malloc(STACK_INIT_SIZE*sizeof(char));
    	if(oprt.base==NULL)return ERROR;
    	oprt.top=oprt.base;
    	oprt.size=STACK_INIT_SIZE;
    	return OK;
    }
    
    Status PushOprd(Operand &oprd,double e)
    {
    	if(oprd.top-oprd.base>STACK_INIT_SIZE)
    	{
    		oprd.base=(double*)realloc(oprd.base,(oprd.size+STACKINCREMENT)*sizeof(double));
    		if(oprd.base==NULL)exit(0);
    		oprd.top=oprd.base+STACK_INIT_SIZE;
    		oprd.size+=STACKINCREMENT;
    	}
    	*oprd.top=e;
    	oprd.top++;
    	return OK;
    }
    
    Status PushOprt(Operator &oprt,ElemType e)
    {
    	if(oprt.top-oprt.base>STACK_INIT_SIZE)
    	{
    		oprt.base=(char*)realloc(oprt.base,(oprt.size+STACKINCREMENT)*sizeof(char));
    		oprt.top=oprt.base+STACK_INIT_SIZE;
    		oprt.size+=STACKINCREMENT;
    	}
    	*(oprt.top)=e;
    	oprt.top++;
    	return OK;
    }
    
    
    Status PopOprd(Operand &oprd,double &e)
    {
    	if(oprd.base==oprd.top)return ERROR;
    	e=*(--oprd.top);
    	return OK;
    }
    
    Status PopOprt(Operator &oprt,ElemType &e)
    {
    	if(oprt.base==oprt.top)return ERROR;
    	e=*(--oprt.top);
    	return OK;
    }
    
    char getOprdTop(Operand oprd)
    {
    	ElemType e;
    	if(oprd.base==oprd.top)return ERROR;
    	e=*(--oprd.top);
    	return e;
    
    }
    
    
    char getOprtTop(Operator oprt)
    {
    	ElemType e;
    	if(oprt.base==oprt.top)return ERROR;
    	e=*(--oprt.top);
    	return e;
    }
    
    char getOprtBase(Operator oprt)
    {
    	ElemType e;
    	if(oprt.base==oprt.top) return ERROR;
    	e=*(oprt.base);
    	return e;
    }
    
    int getOprtSize(Operator oprt)
    {
    	int i=0;
    	if(oprt.base==oprt.top)return 0;
    
    	while(oprt.base!=oprt.top)
    	{
    		oprt.base++;
    		i++;
    	}
    
    	return i;
    }
    
    int getOprdSize(Operand oprd)
    {
    	int i=0;
    	if(oprd.base==oprd.top)return 0;
    
    	while(oprd.base!=oprd.top)
    	{
    		oprd.base++;
    		i++;
    	}
    
    	return i;
    }
    
    
    unsigned char Prior[8][8] = {   //运算符优先级表
      	  '>','>','<','<','<','>','>','>',
    	  '>','>','<','<','<','>','>','>',
    	  '>','>','>','>','<','>','>','>',
    	  '>','>','>','>','<','>','>','>',
    	  '<','<','<','<','<','=',' ','>',
    	  '>','>','>','>',' ','>','>','>',
    	  '<','<','<','<','<',' ','=','>',
    	  '<','<','<','<','<','<','<','='
    };	
    
    char OPSET[OPSETSIZE]={'+' , '-' , '*' , '/' ,'(' , ')' , '#','
    '};
    
    int ReturnOpOrd(char op,char* TestOp)
    {
    	for(int i=0;i<OPSETSIZE;i++)
    		if(op==TestOp[i])
    			return i;
    	return 0;
    }
    
    int In(char op,char* TestOp)
    {
    	int find=0;
    	for(int i=0;i<OPSETSIZE;i++)
    		if(op==TestOp[i])
    			find=1;
    
    	return find;
    }
    
    char Precede(char op1,char op2)//比较运算符的优先级
    {
    	return Prior[ReturnOpOrd(op1,OPSET)][ReturnOpOrd(op2,OPSET)];
    }
    
    double Operate(double a,char op,double b)
    {
    	switch(op){
    	case '+':return a+b;break;
    	case '-':return a-b;break;
    	case '*':return a*b;break;
    	case '/':return a/b;break;
    		
    	}
    }
    
    double EvaluateExpression(Operand &oprd,Operator &oprt)
    {
    	char c;
    	c=getchar();
    
    	while(c!='
    '||getOprtSize(oprt)!=0)//执行到最后操作符栈只剩下换行符
    	{
    		if(!In(c,OPSET))
    		{
    			c=c-'0';
    			PushOprd(oprd,c);
    			c=getchar();
    		}
    		else//如果是操作符
    		{
    			if(getOprtSize(oprt)==0)//判断栈是否为空
    			{
    				PushOprt(oprt,c);
    				c=getchar();
    			}
    			else
    			{
    				switch(Precede(getOprtTop(oprt),c)){
    				case '>':
    					double a,b;
    					if(PopOprd(oprd,a))
    						if(PopOprd(oprd,b))
    						{
    							char operate;
    							PopOprt(oprt,operate);
    							PushOprd(oprd,Operate(b,operate,a));
    						}
    				break;
    				case '=':
    					char ss;
    					PopOprt(oprt,ss);
    					c=getchar();
    					break;
    				case '<':
    					PushOprt(oprt,c);
    					c=getchar();
    					break;
    				}
    			}
    		}
    	}
    	double result;
    	PopOprd(oprd,result);
    	printf("%lf
    ",result);
    	return result;
    }
    
    main()
    {
    	Operand oprd;
    	Operator oprt;
    	InitOprt(oprt);
    	InitOprd(oprd);
    	EvaluateExpression(oprd,oprt);
    	return 0;	
    }

       

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    [转]asp.net页面缓存技术
    UL和LI在div中的高度的IE6下兼容性
    jquery制作的横向图片滚动带横向滚动条TackerScroll
    电脑可以上网,但是qq登陆不上去?
    Introduction to discrete event system学习笔记4.6
    Introduction to Discrete event system学习笔记4.9
    Introduction to discrete event systemsstudy 4.5
    Symbolic synthesis of obserability requirements for diagnosability B.Bittner,M.Bozzano,A.Cimatti,and X.Olive笔记4.16
    Introduction to discrete event system学习笔记4.8pm
    Introduction to discrete event system学习笔记 4.8
  • 原文地址:https://www.cnblogs.com/gaot/p/4859841.html
Copyright © 2011-2022 走看看