C语言版数据结构(从0开始)3.栈

1.栈的概念

栈(stack)又名堆栈,它是一种运算受限的线性表。栈(stack)是限制在表的一端进行插入和删除运算的线性表,通常称插入、删除的这一端为栈顶(top),另一端为栈底(bottom)。当表中没有元素时称为空栈。
向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
via 百度百科
假设栈S=(a1,a2,a3,…an),则a1称为栈底元素,an为栈顶元素。栈中元素按a1,a2,a3,…an的次序进栈,退栈的第一个元素应为栈顶元素。换句话说,栈的修改是按后进先出的原则进行的。因此,栈称为后进先出表。

例:

对于一个栈,给出输入项A、B、C,如果输入项序列由ABC组成,试给出所有可能的输出序列。
qq-735429101

2.顺序栈

2.1顺序栈的概念

栈的顺序存储结构简称为顺序栈,它是运算受限的顺序表。因此,可用数组来实现顺序栈。
因为栈底位置是固定不变的,所以可以将栈底位置设置在数组的两端的任何一个端点;栈顶位置是随着进栈和退栈操作而变化的,故需用一个整型变量top 来指示当前栈顶的位置,通常称 top 为栈顶指针。因此,顺序栈的类型定义只需将顺序表的类型定义中的长度属性改为 top 即可。

2.2 顺序栈的类型定义
        # define stacksize 100
        typedef  char datatype;
           typedef struct {
                 datatype  data[stacksize];
                  int top;
         }seqstack; 

设 s 是 seqstack 类型的指针变量。若栈底位置在向量的低端,即 s–>data[0] 是栈底元素,那么栈顶指针 s–>top 是正向增加的,即进栈时需将 s–>top 加1,退栈时需将 s–>top 减1。因此,s–>top<0 表示空栈s–>top = stacksize-1 表示栈满。当栈满时再做进栈运算必定产生空间溢出,简称“上溢”;当栈空时再做退栈运算也将产生溢出,简称“下溢”。上溢是一种出错状态,应该设法避免之;下溢则可能是正常现象,因为栈在程序中使用时,其初态或终态都是空栈,所以下溢常常用来作为程序控制转移的条件。

2.3顺序栈的基本运算
置空栈
void initstack(seqstack *s)
 {
	 s–>top=-1;
 }
判断栈空
int stackempty(seqstack *s)
{
	return(s–>top==-1);
}
判断栈满
int stackfull(seqstack   *s)
{
	return(s–>top==stacksize-1);
}
进栈
void  push(seqstack  *s,datatype  x)
{
	if(stackfull(s))error(“stack overflow”);
	s–>data[++s–>top]=x;
} 
出栈
datatype pop(seqstack *s)
{
	if(stackempty(s))
		error(“stack underflow”);
	x=s–>data[top];
	s–>top--;
	return(x);
}
取栈顶元素
datatype  stacktop(seqstack  *s)
{
	if(stackempty(s)
		error(“stack is empty”);
	return s–>data[s–>top];
}

3.链栈

3.1链栈的概念

栈的链式存储结构称为链栈,它的运算是受限的单链表,插入和删除操作仅限制在表头位置上进行。由于只能在链表头部进行操作,故链表没有必要像单链表那样附加头结点。栈顶指针就是链表的头指针。

3.2链栈的特点
  • 链式栈无栈满问题,空间可扩充
  • 插入与删除仅在栈顶处执行
  • 链式栈的栈顶在链头
  • 适合于多栈操作(可实现两个堆栈共享空间
    qq-735429101
3.3链栈的类型定义
typedef int datatype;
typedef struct node
{
	datatype data;
	struct node *next;
}linkstack; 
3.4链栈的基本运算
进栈
linkstack *PUSHLSTACK(linkstack *top, datatype x)
{
	linkstack *p;
	p=malloc(sizeof(linkstack));
	p->data=x; p->next=top;
	return p;
}
出栈
linkstack *POPLSTACK(linkstack *top, datatype datap)
{
	linkstack *p;
	if(top==NULL) 
	{
		printf("under flow\n");
		return NULL;
	}
	else
	{
		*datap=top->data;
		p=top;
		top=top->next;
		free(p);
		return top;
	}
}

4.栈的应用

4.1数制转换

十进制N和其它进制数的转换是计算机实现计算的基本问题,其解决方法很多,其中一个简单算法基于下列原理:
N=(n div d)*d+(n mod d)
( 其中:div为整除运算,mod为求余运算)
例如 (1348)10=(2504)8,其运算过程如下:

nn div 8n mod 8
13481684
168210
2125
202

C语言实现:

void conversion()
{
	initstack(s);
	scanf ("%",&n);
	while(n)
	{
		push(s,n%8);
		n=n/8;
	}
	while(! stackempty(s))
	{
		pop(s,e);
		printf("%d",e);
	}
}
4.2文字编辑器

输入的一个字符是错的之后,可以再输入一个 ‘#’ ,表示前一个字符是错的,如果发现当前行输入的错误太多,可以输入一个退行符 ‘@’ ,表示当前行都无效。

seqstack s;
int edit()
{
	char c;
	setnull(&s);
	c=getchar();
  while(c!='*')
  {
	  if (c=='#')pop(&s);
	  else if(c=='@')sttnull(&s);
	  else push(&s,c);
	  c=getchar();
   }
} 
4.3表达式计算

中缀表达式:A+(B-C/D)×E
后缀表达式:ABCD/-E×+

后缀表达式特点
  • 1、与相应的中缀表达式中的操作数次序相同
  • 2、没有括号
处理规则
  • 1、如为操作数,直接输出到队列;
  • 2、如当前运算符高于栈顶运算符,入栈;
  • 3、如当前运算符低于栈顶运算符,栈顶运算符退栈, 并输出到队列,当前运算符再与栈顶运算符比较;
  • 4、如当前运算符等于栈顶运算符,且栈顶运算符为 “(”,当前运算符为“)”,则栈顶运算符退栈, 继续读下一符号;
  • 5、如当前运算符等于栈顶运算符,且栈顶运算符为 “#”,当前运算符也为“#”,则栈顶运算符退栈,继续读下一符号;
    qq-735429101
步骤
步骤中缀表达式stack输出
1A+(B-C/D)×E##
2+(B-C/D)×E##A
3(B-C/D)×E## +A
4B-C/D)×E## +(A
5-C/D)×E## + (A B
6C/D)×E## + ( -AB
7/D)×E## + ( -ABC
8D)×E## + ( - /ABC
9)×E## + ( - /ABCD
10×E## + ( -ABCD/
11×E## + (ABCD/-
12×E## +ABCD/-
13E## + ×ABCD/-
14## + ×ABCD/-E
15## +ABCD/-E×
16##ABCD/-E×+

文章内容来源于博主老师传授、自身理解以及网络收集

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值