数据结构--栈、队列、串

数据结构–栈、队列、串

栈、队列、串

从数据结构的角度看,栈和队列也是线性表。

  • (stack)是限定仅在表尾进行插入和删除操作的线性表。因此,对栈来说,表尾端有其特殊含义,称为栈顶,相应地,表头端称为栈底。不含元素的空表称为空栈。
  • 又被称为后进先出(last in first out)的线性表(简称LIFO结构)。

栈的表示和实现

  • 顺序栈,即栈的顺序存储结构是利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针top指示栈顶元素在顺序栈中的位置。
    对栈的初始化,一个较合理的做法:先为栈分配一个基本容量,然后在应用过程中,当栈的空间不够使用时再逐段扩大。 为此,可设定两个常量:STACK_INT_SIZE(存储空间初始分配量)和STACKINCREMENT(存储空间分配增量),并以下述类型作为顺序栈的定义。
	typedef struct {
		SElemType  *base;
		SElemType  *top;
		int  stacksize;
	}

其中,stacksize指示栈的当前可使用最大容量。栈的初始化操作为:按设定的初始分量进行第一次存储分配,base可称为栈底指针,在顺序栈中,它始终指向栈底的位置,若base的值为NULL,则表明表结构不存在。称top为栈顶指针,其初值指向栈底,即top=base可作为栈空的标记,每当有插入新的栈顶元素时,指针top增1;删除栈顶元素时,指针top减1,因此,非空栈中的栈顶指针始终在栈顶元素的下一个位置上。如图:
在这里插入图片描述

  • 链栈,栈的链式表示。
  • 的应用
    Q1:十进制数 N N N和其他 d d d进制转换。
    公式: N N N = ( N N N div d d d) * d d d + N N N mod d d d(其中div为整除运算,mod为求余运算)。
    例如:(1348)10 = (2504)8 ,其运算如下:
			N                         N div 8                   N mode 8
		   1348                         168                        4
		    168                          21                        0
		     21							  2                        5
		      2                           0						   2

利用栈的特性编写程序。

void conversion() {
	// 对于输入的任意一个非负十进制整数,打印输出与其等值的八进制
	InitStack(S) //创造空栈
	scanf("%d",N);
	while(N) {
		Push(S, N % 8);
		N = N / 8;
	}
	while(!StackEmpty(S)) {
		Pop(S,e);
		printf("%d",e);
	}
}

Q2:括号匹配的检测 [([] [])]
解答:在算法中设置一个栈,接收第一个括号的时候入栈,接收第二个括号的时候判断是否是与第一个括号(栈顶的数据)匹配的括号,如果是,则第一个括号出栈,如果不是第二个继续入栈,依次类推,最后如果栈不是空的,则说明括号不匹配,否则是匹配的。

Q3:迷宫求解(求迷宫中从入口到出口的所有路径–穷举求解法
在这里插入图片描述
Q4:表达式求值(3 * (7 - 2))
算法的基本思想:

  1. 首先置操作数为空栈,表达式起始符“#”为运算符栈的栈底元素
  2. 依次读取表达式中的每一个字符,若是操作数则进OPND(存放数字)栈,若是运算符则和OPTR栈的栈顶运算符比较优先级后 做相应的操作,直至整个表达式求值完毕(即OPTR栈的栈顶元素和当前读入的字符均为‘#’)。
    算法优先级列表
    运算符优先级
例如:3 *7 - 2)
步骤    OPTR栈    OPND栈          输入字符            主要操作
1         #                   3 *7 - 2)#      PUSH(OPND,3)
2         #         3           *7 - 2)#      PUSH(OPTR,*)
3         #*        37 - 2)#      PUSH(OPTR,‘(’)
4         #*3               7 - 2)#      PUSH(OPND,7)
5         #*3 7               - 2)#      PUSH(OPTR,-)
6         #*-     3 7                 2)#      PUSH(OPND,2)
7         #*-     3 7 2                )#      operate(7’,‘-’,‘2)
8         #*3 5                  )#      POP(OPTR){消除一对括号}
9         #*        3 5                    #      operate(3’,‘*’,‘5)
10        #         15                     #      RETURN 15; 
// OPTR栈:存放运算符    OPND栈:存放操作数     operate():运算操作函数
// POP():出栈   PUSH():入栈    
// 栈顶运算符优先级 < 读入的运算符 运算符入栈
// 栈顶运算符优先级 = 读入的运算符 栈顶运算符出栈(运算符消去)
// 栈顶运算符优先级 < 读入的运算符 栈顶运算符出栈,并退栈操作数,进行运算操作

栈与递归的实现

栈还有一个重要应用是在程序设计语言中实现递归。

递归是程序设计的一个强有力工具。其一,有很多数学函数是递归定义的。
比如:
阶乘函数
F a c t ( n ) = { 1 若 n = 0 n ∗ F a c t ( n ) 若 n &gt; 0 Fact(n)=\begin{cases} 1 &amp; 若n = 0 \\ n * Fact(n) &amp;若n &gt; 0 \\ \end{cases} Fact(n)={1nFact(n)n=0n>0
2阶Fibonacci数列
F i b ( n ) = { 0 若 n = 0 1 若 n = 1 F i b ( n − 1 ) + F i b ( n − 2 ) 其 他 情 形 Fib(n)=\begin{cases} 0 &amp; 若n = 0 \\ 1 &amp; 若n = 1 \\ Fib(n - 1) + Fib(n - 2) &amp;其他情形 \\ \end{cases} Fib(n)=01Fib(n1)+Fib(n2)n=0n=1
Ackerman函数
A c k ( m , n ) = { n + 1 若 m = 0 A c k ( m − 1 , n ) 若 n = 0 A c k ( m − 1 , A c k ( m , n − 1 ) ) 其 他 情 形 Ack(m,n)=\begin{cases} n+1 &amp; 若m = 0 \\ Ack(m - 1,n) &amp; 若n = 0 \\ Ack(m - 1,Ack(m,n-1)) &amp;其他情形 \\ \end{cases} Ack(m,n)=n+1Ack(m1,n)Ack(m1,Ack(m,n1))m=0n=0
一个递归函数,在函数的执行函数中,需要多次进行自我调用。
两个函数之间调用的情形:

通常,当在一个函数的运行期间调用另一个函数时:
在运行被调用函数之前,系统需先完成3件事
(1)将所有的实在参数、返回地址等信息传递给调用函数保存;
(2)为被调用函数的局部变量分配存储区;
(3)将控制转移到被调用函数的入口;
而从被调用函数返回调用函数之前,系统也要完成3件工作
(1)保存被调函数的计算结果;
(2)释放被调函数的数据区;
(3)依照被调函数保存的返回地址将控制转移到调用函数。
当有多个函数构成嵌套调用的时候,按照"后调用先返回"的原则。
上述函数之间的信息传递和控制转移必须通过"栈"来实现,即系统将整个程序运行时所需的数据空间安排在一个栈中,每当调用一个函数时,就为它在栈顶分配一个存储区;每当一个函数退出时,就释放它的存储区,则当前正在运行的函数的数据区必须在栈顶

队列

和栈相反,队列(Queen)是一种先进先出(first in frist out)的线性表。
它只允许在表的一端进行插入,而在另一端进行删除。
在队列中,允许插入的一端叫做队尾(rear),允许删除的一端则称为队头(front)
在这里插入图片描述

除了栈和队列之外,还有一种限定性数据结构是双端队列(deque).双端队列是限定插入和删除操作在表的两端(或者一个端点允许插入和删除,另一端点只允许插入/或者一个端点允许插入和删除,另一端点只允许删除)进行的线性表。

和线性表类似,队列也可以有两种存储表示

  • 链队列——队列的链式表示和实现

用链表表示的队列简称链队列,一个链队列需要两个分别指示队头和队尾的指针(分别称为头指针和尾指针)
在这里插入图片描述

  • 循环队列——队列的顺序表示和实现
    和顺序栈类似,在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放从队列头到队列尾元素之外,尚需附设两个指针front和rear分别指示队列头元素及队列尾元素的位置。
    在这里插入图片描述
    为了在C语言中描述方便起见,在此我们约定:初始化建立队列时,令front = rear = 0每当插入新的队列尾元素时,“尾指针增1”;每当删除队列的头元素时,“头指针增1”。在非空队列中,头指针始终指向队列头元素,而尾指针始终指向队列尾元素的下一个位置。
    循环链表
    为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列(Circular Queue)。这种循环队列可以以单链表的方式来在实际编程应用中来实现。

(string)(或字符串)是由零个或多个字符组成的有序序列,一般记作s = ‘a1,a2,…an’ (n >= 0)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值