数据结构之栈和队列

一、栈的定义及抽象数据类型

  1. 栈(stack)又称堆栈,它是运算受限的线性表,其限制是仅允许在表的一端进行插入和删除操作,不允许在其他任何位置进行插入、查找、删除等操作。表中进行插入、删除操作的一端称为栈顶(top),栈顶保存的元素称为栈顶元素。相对的,表的另一端称为栈底(bottom)
  2. 基本名词概念:
  • 空栈:栈中没有数据元素
  • 进栈(入栈):向一个栈中插入元素
  • 出栈(退栈):从一个栈中删除元素
  • LIFO(Last in First out后进先出表):栈的插入和删除只能在栈顶进行,只能先进后出。
    堆栈及入栈/出栈
  1. 栈的基本操作:

stack.getSize():返回堆栈的大小,即数据元素的个数
stack.isEmpty():如果堆栈为空返回 true,否则返回 false
stack.push(e):数据元素 e 入栈
stack.pop():栈顶元素出栈
stack.peek():获取栈顶元素,但不出栈

二、栈的顺序存储实现

  1. 顺序存储结构:使用顺序存储结构实现的堆栈,即利用一组地址连续的存储单元依次存放堆栈中的数据元素
    • 由于栈操作都是在栈顶完成的,实现时需要一个指针top 动态指示栈顶元素在数组中的位置。top可以用栈顶元素所在下标来表示,top = -1 表示空栈
    • 关于堆栈最大容量问题,只需要为其分配一个基本容量(可以设置),容量不够时再倍增存储空间,所需时间复杂度均摊到每个元素时间为O(1)。
  2. 链式存储结构:链栈即采用链表作为存储结构实现的栈。
  3. 单链表存储线性表:选择单链表的头部作为栈顶,此时,入栈、出栈等操作可以在Ο(1)内完成。使用带头结点的单链表时,结点的插入和删除都在头结点之后进行;使用不带头结点的单链表时,结点的插入和删除都在链表的首结点上进行。不带头结点的单链表如下图:
    链表示意图
    出栈:不管堆栈在删除栈顶元素之后,栈是否为空,出栈操作都是将top 后移。
    入栈:
SLNode q = new SLNode(e,top); //结点 q 的 next 域指向 top,不管 top 是否为 Null 
top = q;

三、队列

1、概念:队列(queue)简称队,它同堆栈一样,也是一种运算受限的线性表,其限制是仅允许
在表的一端进行插入,而在表的另一端进行删除。在队列中把插入数据元素的一端称为
队尾
(rear)
,删除数据元素的一端称为队首(front)。向队尾插入元素称为进队或入队,新元素入队后成为新的队尾元素;从队列中删除元素称为离队或出队,元素出队后,其后续元素成为新的队首元素。
2、基本操作:

queue.getSize():返回队列的大小,即数据元素的个数
queue.isEmpty():如果队列为空返回 true,否则返回 false
queue.enqueue(e):数据元素 e 入队
queue.dequeue():队首元素出队
queue.peek():获取队首元素,但不出队

3、队列的顺序存储:(4-5)

  • 普通队列:用普通数组实现的队列,特点是以用一个指针 last 来指示队尾,使得 enqueue 运算可在Ο(1)时间内,在执行 dequeue 时,为了删除队首元素,必须将数组中其他所有元素都向前移动
    一个位置,执行 dequeue 就需要Ο(n)时间。
  • 循环队列:想数组A[0… capacity-1]中的单元不是排成一行,而是围成一个圆环,即 A[0]接在 A[capacity-1]的后面称之为循环数组。用循环数组实现的队列称为循环队列。
    4、循环队列:中从队首到队尾的元素按逆时针
    方向存放在循环数组中一段连续的单元中。并且直接用队首指针 front 指向队首元素所在的
    单元,用队尾指针 rear 指向队尾元素所在单元的后一个单元。如图所示,front = 0, rear = 3。出栈入栈时间复杂度:O(1)。
    循环数组
    5、满队列与空队列:如图(a)所示,当删除元素时,队首追上队尾,front = rear,此时为空队列;如图(c)所示,当队尾追上队首时,front = rear,此时为满队列。如何表征满队列与空队列:
  • 少使用一个存储空间,当队尾指针的下一个单元就是队首指针所指单元时,则停止入队,此时队尾指针就追不上队首指针,亦不会有front = rear,队满条件(rear + 1) % capacity = front,队空条件是 front = rear
  • 增设一个标志,以区别队列是”空“还是”满“;
    循环队列
    综上所述,见下表:
    在这里插入图片描述
    6、链式存储:使用单链表来实现。采用带头结点的单链表结构,为了操作方便,设置两个指针,一个队首指针和一个队尾指针,如图(a)所示,队首指
    针指向队首元素的前一个结点,即始终指向链表空的头结点,队尾指针指向队列当前队尾元素所在的结点。当队列为空时,队首指针与队尾指针均指向空的头结点。
    链式存储结构

四、堆栈的应用

  1. 进制转换:换是一种常见的数值计算问题。实现进制转换的一种简单方法是重复以下两步,直到 N 等于 0。
    X = N mod d //其中 mod 为求余运算
    N = N div d //其中 div 为整除运算
    进制转换
//十进制正整数---> 八进制
public void baseConversion(int i){
    
 Stack s = new StackSLinked(); 
 while (i>0){
    
 s.push(i%8+""); 
 i = i/8; 
 } 
 while (!s.isEmpty()) System.out.print((String)s.pop()); 
 }
  1. 括号匹配检测:假设表达式中包含三种括号:圆括号、方括号和花括号,并且它们可以任意相互嵌套。该问题可按“期待匹配消解”的思想来设计算法:算法需要一个堆栈,在读入字符的过程中,
    • 如果是左括号,则直接入栈,等待相匹配的同类右括号;
    • 如果是右括号,且与当前栈顶左括号匹配,则将栈顶左括号出栈,如果不匹配则属于不合法的情况。另外如果碰到一个右括号,而堆栈为空,
      说明没有左括号与之匹配,属于非法情况;
    • 字符读完,而堆栈不为空,说明有左括号没
      有得到匹配,也属于非法情况。
    • 当字符读完同时堆栈为空,并且在匹配过程中没有发现不匹配的情况,说明所有的括号是匹配的。
public boolean 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值