数据结构——栈和队列 01

1.顺序栈——用一块连续空间顺序存放栈元素
栈的数据结构定义:

#define STACK_SIZE 64;  //栈容量设置
typedef struct Stack
{
    datatype stack[STACK_SIZE];//栈空间
    int top;//栈顶指针
}   SeqStack;

约定:
栈空:Top=-1
栈满:Top=STACK_SIZE-1

1)初始化:置空栈

 void InitStack(SeqStack *s)
 {
 	s->top=-1;
 }

2)判断栈空

 /*=======================================
函数功能:判断顺序栈是否为空
函数输入:顺序栈地址
函数输出:1——栈空;0——栈非空
=========================================*/
    int StackEmpty_SqStack(SeqStack *s)
     {
            return( s->top == -1 );
     }

3)进栈(注意区别传值调用和传址调用)
栈状态:栈未满或栈满
伪代码描述:若栈满则 return FALSE;
修改栈顶指针top++;
在栈顶指针指向位置放入x;
return TRUE.

/*=======================================
函数功能:顺序栈进栈操作
函数输入:顺序栈地址,进栈元素值
函数输出:0——栈上溢,操作失败;1——操作正常
=========================================*/
int  Push_SqStack(SeqStack *s,  datatype  x)
{       
      if ( s->top == STACK_SIZE-1)    return  FALSE;  //栈上溢
      else    
      { 
          s->top++;
          s->stack[s->top]=x;
       }
      return TRUE;
 }

4)出栈
测试情形:栈非空,栈顶指针>0 else =0; 栈空,栈顶指针=-1。

伪代码描述:若栈空,则 return FALSE;
记录栈顶元素值x;
修改栈顶指针:top–;
return TRUE。

/*=====================================
函数功能:顺序栈出栈操作
函数输入:顺序栈地址,(出栈元素地址)
函数输出:0——栈下溢,操作失败;1——操作正常
=========================================*/
int  Pop_SqStack(SeqStack *s, datatype *x)
{    
      if ( s->top == -1) return FALSE;
      else    
      {  
             *x= s-> stack[s-> top];    //取栈顶元素的值
              s-> top--;                //修改栈顶指针
       }
     return TRUE;
 } 

顺序栈存在栈满以后就不能再进栈的问题,这是因为用了定长的数组存储栈的元素。解决的方法,可以使用链式存储结构,让栈空间可以动态扩充。

2.链栈的基本操作

关于链表和链栈:都是采用离散的方式存储;存储元素分别为线性表元素和栈元素;而链栈是运算受限的单链表,其插入和删除操作仅限制在表头的位置上进行。
因为只能在链表头部进行操作,故链栈不需要附加头结点
在这里插入图片描述
链栈数据结构的描述:

typedef int datatype;
typedef struct node      	//结点
{ 
  datatype data;
  struct node *next;      	//链指针
} LinkStack; 
LinkStack  *top;      	//栈顶指针

1 )进栈;
步骤:申请一个新结点p,并赋值为x;
将p结点链在栈顶;
修改栈顶指针;
返回栈顶指针。

ListStack *PushLStack(ListStack *top, datatype x)
{
	LinkStack *p;
	p=malloc(sizeof(LinkStack));
	p->data=x;
	p->next=top;
	top=p;
	return top;   //需注意进栈前,栈底指针赋 NULL	
}

在这里插入图片描述
return top:将新建的链栈结点链入,top指针改变让下个结点链入新top。

扫描二维码关注公众号,回复: 8842506 查看本文章

需注意,链入的第一个结点其链入栈顶结点为NULL,即栈底的next值改为0。

2)出栈;
伪代码:若栈非空;
记录栈顶结点地址p,元素值datap;
修改栈顶指针top;
释放结点p。

/*==================================================
函数功能:链栈的出栈操作
函数输入:栈顶指针、(出栈元素)
函数输出:栈顶指针
===================================================*/
LinkStack * PopLStack(LinkStack *top,  datatype *datap)
{ LinkStack *p;
     if ( top != NULL)
        {    *datap=top->data;
               p=top;
               top=top->next;
               free(p);
         }
     return top; //栈空时,返回NULL
}

在这里插入图片描述
共享栈——多栈共享邻接空间
常常一个程序中要用到多个栈,为了不发生上溢错误,必须给每个栈预先分配一个足够大的存储空间;另一方面,若每个栈都预分配一个足够大的存储空间,势必造成系统空间紧张;若让多个栈共用一个足够大的连续存储空间,则可利用栈的动态特性使它们的存储空间互补。
例两个栈共享一个一维空间S(StackSize),两个栈的栈底设置在数组的两端,当栈顶相遇,栈满。

#define STACK_SIZE 64    //两栈共享的存储空间大小
typedef struct
{
    datatype stack[STACK_SIZE];
    int top1, top2;      //两栈的栈顶指针
}DSegStack;

栈(STACK)
凡应用问题求解的过程具有"后进先出"的天然特性的话,则求解的算法中也必然需要利用"栈"。

1.十进制数N到R进制数d的转换;
算法:
N=(n div d)*d+n mod d (div为整除运算,mod为求余运算)
例:(1348)10=(2504)8
在这里插入图片描述
程序实现

//对于输入的任意一个非负十进制整数n,打印输出与其等值的八进制数
void conversion(SeqStack *S, int n) {
	int e;
	while (n) {
		Push_SqStack(S,n%8);// "余数"入栈
		n = n/8;  //非零"商"继续运算
	}
	while (!StackEmpty_SqStack(S)) { //栈非空,显示结果
		Pop_SqStack(S,&e);
		printf("%d",e);
	}
}

2.栈实现函数的递归
数据结构与算法分析新视角:p 125

问题:实现等差级数1+2+3+…+value的求和

递归的实现方法
(1)递归边界条件: iterate=value 当value=1
(2)递归继续条件 iterate=value+iterate(value-1) 当value>1

int  iterate( int  value )  
{  
    if (value == 1)   return 1; 
    return sum = value +  iterate(value -1);  
} 

3.表达式求值

1)后缀表达式(Postfix Notation)
———运算符在操作数之后
运算符紧跟在两个操作数之后的表达式叫后缀表达式
如:
中缀表达式(AB/C)
对应的后缀表达式为 (AB
C/)

后缀表达式计算:
表达式:1 + ( 5 - 6 / 2 ) * 3
后缀表达式:1 5 6 2 / - 3 * + #
注:为运算方便在后缀表达式最后加一个结束标志‘#’
在这里插入图片描述
算法设计:
在这里插入图片描述

void value(char suffix[], int *c)
{
	char *p,ch;
	InitStack(S);//初始化栈S
	p=suffix;   
	While(*p!='#')//表达式未结束,“#”结束标识
	{
		if(!isoperator(ch))//判断ch非运算符
		{
			push(S,ch);    //压栈
		}
		else
		{
			pop(S,a);    //弹栈取操作数a
			pop(S,b);    //弹栈取操作数b
			push(S,operate(a,ch,b));//a与b的计算结果压栈
		}
		p++;
	 } 
	 pop(S,*c);//计算结果赋给 c
 } 

2)中缀转后缀规则
转换过程中:要用到一个存放运算符的栈S,一个保存后缀表达式的数组suffix[];
从左到右扫描中缀表达式时,将遇到五类元素:操作数、左括号、运算符、右括号和结束符#。
在这里插入图片描述
例:将中缀表达式“1+2-3#”转换为后缀表达式
在这里插入图片描述
例:1+((2+3)×4)-5#
在这里插入图片描述
3)中缀转前缀规则
在这里插入图片描述
在这里插入图片描述

发布了9 篇原创文章 · 获赞 3 · 访问量 170

猜你喜欢

转载自blog.csdn.net/herui7322/article/details/104060800