数据结构—栈与队列【顺序存储、链式存储、卡特兰数、优先级队列】(二)

简介: 数据结构—栈与队列【顺序存储、链式存储、卡特兰数、优先级队列】

(四) 链栈


         一、什么是链栈?


                       使用链式存储的栈,就是链栈。


                       插入和删除操作在栈顶进行,也就是链表的尾端。


                       存储单元由2部分组成:数据域 data 和指针域 next 。


                        使用top栈顶指针用于指向栈尾


ff455bc4b417406bb8f8f4eb77df216f.png

二、链栈类 【LinkStack】

package data.linear_table.stack_queue;
import data.linear_table.node.Node;
//链栈类
public class LinkStack implements IStack {
    private Node top ;      //栈顶元素的引用
    //将栈置空
    @Override
    public void clear() {
        top = null ;
    }
    //判断链栈是否为空
    @Override
    public boolean isEmpty() {
        return top == null ;
    }
    //求链栈的长度
    @Override
    public int length() {
       //{...} 
        return 0 ;
    }
    //取栈顶元素并返回其值
    @Override
    public Object peek() {
        //栈如果不为空
        if (!isEmpty()) {
            //返回栈顶元素
            return top.data ;
        }else {
            return null ;
        }
    }
    //入栈
    @Override
    public void push(Object x) throws Exception {
        //{...}             
    }
    //出栈
    @Override
    public Object pop() {
        // {...}
        return null ;
    }
    //输出栈中所有数据元素(从栈顶元素到栈底元素)
    public void display() {
        Node p = top ;          //初始化,p指向栈顶元素
        while (p != null ) {    //输出所有非空结点的数据元素值
            System.out.print(p.data.toString()+" ");
            p = p.next ;        //p指针向后移
        }
    }
}


注: 代码中 ” {....}“ 处,会在后面单独进行讲解。


1. public class LinkStack {
2. private Node top;      //栈顶指针
3. }


算法:链栈的长度

  //求链栈的长度
    @Override
    public int length() {
        Node p = top ;      //初始化,p指向栈顶元素
        int length = 0 ;    //length为计数器
        //从栈顶元素开始向后查找,直到p为空
        while (p != null ) {
            p = p.next ;    //p指向后继结点
            length++ ;      //长度增加1
        }
        return length ;
    }

算法:入栈

public void push(Object x) {
    Node p = new Node(x);   // 创建新结点p
    p.next = top;    // 1.p的指针域指向栈顶元素
    top = p;      // 2.栈顶指针top指向新结点p
}

算法:出栈

public Object pop() {
    if(top == null) {     //空栈 isEmpty()
        return null; 
    } else {
        Node p = top;       // 1 存放栈顶元素
        top = top.next;     // 2 将top指向栈顶的下一个元素
        return p.data;      // 3 返回栈顶元素数据
    }
}

(五) 队列


       一、什么是队列?


                        队列是一个特殊的线性表。


                       只允许在队尾进行插入操作


                        只允许在队首进行删除操作


----------------------------------------------------------------------------


        二、队列的相关术语?


                        队尾rear:进行插入操作的一端。


                        队首front :进行删除操作的一端


                       入队offer : 进行插入操作,称为入队


                       出队 poll : 进行删除操作 , 称为出队

b54d5e43866e49c9bb9bab5116282360.png

三、 队列有哪两种存储方式 ?


                        使用顺序存储的称为顺序队列 。


                        使用链式存储的称为链队列 。


----------------------------------------------------------------------------


四、队列的抽象数据类型Java接口【IQueue】

package data.linear_table.stack_queue;
//队列的抽象数据类型Java接口
public interface IQueue {
    public void clear() ;   //置队成空队列
    public boolean isEmpty() ;  //判断队列是否为空
    public int length() ;   //队列中数据元素的个数
    public Object peek() ;  //取队列首元素
    public   void offer(Object x) throws Exception;  //将元素x插入到队列中使用成为新的队尾元素
    public Object poll() ;   //删除对首元素并返回其值。若队列为空,则返回null
}

(六) 顺序队列


        一、什么是顺序队列?


·                         顺序队列的存储结构中,需要分配一块地址连续的存储区域来一次存放队列中从队首到队尾的所有元素。


        二、关于队列的那些操作?


                        front表示队首,进行出队操作时,front进行计数。


                       rear表示队尾,进行入队操作时,rear进行计数。


                        front == rear == 0 为空队列。


                       入队操作:


97f2b06a3cfa441581b797823a33890a.png


                        出队操作:

11d71d82684b4f0f8e4fcfb6b5b52051.png

     


         三、队列存在的问题“假溢出”


                        因为顺序队列的多次入队和出队操作后出现有存储空间,但是又不能顺序入队的溢出现象,称为“假溢出”。


                       假溢出,数组的最后一个元素已经添加数据,但队列没有满 。


1a4d37f3e92849799b477f76a348d5ec.png


                         解决方案:使用循环队列解决“假溢出”问题。将顺序队列所使用的存储空间看成是一个逻辑上首尾相连的循环队列。


915b2a20d4a04a808ca2b6f621cfb4bc.png


 ----------------------------------------------------------------------------


(七) 循环顺序队列


        一、什么是循环顺序队列?


                        在逻辑上队首和队尾连接在一起。


                       存在的问题:队首front和队尾rear重叠时,无法区分队满还是队空。


193344d7c4e04c8ab91dbe5c00df04f6.png


                        解决方案 :


                               方案1:设计一个计数器,出入队累计法。(整数变量num,入队+1,出队-1,如果num=0就是空)。判断条件为:num == 0 为队空;num > 0 && front == rear 为队满。


                               方案2:设计一个标识变量法。(flag=0出队,flag=1入队,重叠后0表示空,1表示满)。判断条件为:front == rear && flag == 0 为队空;front == rear && flag == 1 为队满。


                               方案3:少用一个存储单位。当顺序存储空间为maxSize时,只允许最多存放maxSize -1个数据元素。判断条件为:


// 队列空
front == rear;
// 队列满
(rear + 1) % maxSize == front;

2d861fd7d7944b75a6b8cf994c0267b8.png

详解   front == (rear+1) % maxSize 为 队满 :

547c5864a6e045ba884d7ecfd8cf5925.png




相关文章
|
1月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
21 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
6月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
297 77
|
5月前
|
算法 调度 C++
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
75 11
|
5月前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
6月前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
216 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
6月前
|
存储 算法 C++
【C++数据结构——图】图的邻接矩阵和邻接表的存储(头歌实践教学平台习题)【合集】
本任务要求编写程序实现图的邻接矩阵和邻接表的存储。需掌握带权有向图、图的邻接矩阵及邻接表的概念。邻接矩阵用于表示顶点间的连接关系,邻接表则通过链表结构存储图信息。测试输入为图的顶点数、边数及邻接矩阵,预期输出为Prim算法求解结果。通关代码提供了完整的C++实现,包括输入、构建和打印邻接矩阵与邻接表的功能。
227 10
|
6月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
157 7
|
8月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
745 9
|
8月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
182 58