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

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

循环顺序队列类 !


                        循环顺序队列,在逻辑上是一个循环,也就是队首和队尾连接


65c6eabceeb5452694523d9f76885dac.png


                         循环顺序队列,在物理上就是一个数组 。


ae1466faa1b74954be325234719cd572.png


        循环顺序队列类Java语言描述【SqQueue】


—— 实现队列接口IQueue

package data.linear_table.stack_queue;
//循环队列类
public class SqQueue implements IQueue {
    private Object[] queueElem ;    //队列的存空间
    private int front ;             //队首的引用,若队列不为空,指向队首元素
    private int rear ;              //队尾的引用,若队列不为空,指向队尾元素的下一个存储位置
    //循环队列类的构造函数
    public SqQueue(int maxSize) {
        front = rear = 0 ;      //队首、队尾初始化为0
        queueElem = new Object[maxSize] ;       //为队列分配maxSize个存储单元
    }
    //队列置空
    @Override
    public void clear() {
        front = rear = 0 ;
    }
    //判断队列是否为空
    @Override
    public boolean isEmpty() {
        return front == rear;
    }
    //求队列的长度
    @Override
    public int length() {
        //(尾 - 头 + 队列长度) % 队列长度
        return (rear - front + queueElem.length)%queueElem.length ;
    }
    //读取队首元素
    @Override
    public Object peek() {
        if (front == rear) {
            //队列为空
            return null ;
        }else {
            //返回队首元素
            return queueElem[front];
        }
    }
    //入队
    @Override
    public void offer(Object x) throws Exception {
         //{..... }
    }
    //出队
    @Override
    public Object poll() {
        //{..... }
       return null ;
    }
    //输出队列中的所有数据元素(从队首到队尾)
    public void display () {
        //队列不为空
        if (!isEmpty()) {
            for (int i = front ; i != rear ; i = (i+1)% queueElem.length ) {
                System.out.print(queueElem[i].toString()+" ");
            }
        }else {
            System.out.println("此队列为空");
        }
    }
}

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

                       算法:入队

4fef1e1aebeb44eb86960bc47864f035.png


    //入队
    @Override
    public void offer(Object x) throws Exception {
        //判断是否已经满了,如果已经满了,抛异常
        //例头front = 0 ; rear = 4 ; 即queueElem.length = 5 ;
        //即:(rear+1) % queueElem.length = 5 % 5 = 0 = front  ;满足,即队列满
        if ( (rear+1) % queueElem.length == front) {
            throw new RuntimeException("队列满了");
        }else {
            //没有满进行入队操作
            //入队只能从队尾进行添加。队尾rear
            queueElem[rear] = x ;
            rear = (rear + 1) % queueElem.length ;     //队尾rear累加1 , 但最后时需要归零
        }
    }

ba41fff724364befbb96eb76ae4f4abf.png

    //出队
    @Override
    public Object poll() {
        if (front == rear) {
            //队列为空
            return null ;
        }else {
            Object t = queueElem[front] ;       //记录出队的元素
            front = (front+1) % queueElem.length ;      //重新赋值队首+1 ,并且要归0
            return t ;                  //返回队列的队首元素
        }
    }


(八) 链队列


        一、什么是链队列?


                        队列采用链式存储结构的队列叫链队列。


                        用两个指针front和rear 来分别队首元素和队尾元素。


41a474ac752e4d359ea5ab0282a51a8b.png


           二、链队列类【LinkQueue】


链表所需结点类:

package data.linear_table.node;
//单链表:结点类
public class Node {
    public Object data ;  //存放结点值
    public Node next ;    // 后继结点的引用
    //无参时的构造函数
    public Node() {
        this(null,null);
    }
    //带一个参数时的构造函数
    public Node(Object data) {
        this(data,null);
    }
    //带两个参数时的构造函数
    public Node(Object data , Node next) {
        this.data = data ;
        this.next = next ;
    }
}

LinkQueue类

 package data.linear_table.stack_queue;
import data.linear_table.node.Node;
//链队列类
public class LinkQueue implements IQueue {
    private Node  front ;   //队首指针
    private Node  rear ;    //队尾指针
    //链队列类的构造函数
    public LinkQueue () {
        front = rear = null ;
    }
    //队列置空
    @Override
    public void clear() {
        front = rear = null ;
    }
    //判断队列是否为空
    @Override
    public boolean isEmpty() {
        return front == null ;
    }
    //求队列的长度
    @Override
    public int length() {
        Node p = front ;
        int length = 0 ;
        while (p != null ){
            p = p.next  ;
            length++ ;
        }
        return length ;
    }
    //取首元素
    @Override
    public Object peek() {
        if (front != null ) {       //队列非空
            return front.data ;     //返回队首结点数据域值
        } else  {
            return null ;
        }
    }
    //入队
    @Override
    public void offer(Object x) throws Exception {
        //{...}
    }
    //出队
    @Override
    public Object poll() {
        //{...}
        return null
    }
}

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

                       算法:入队

eb5203853f724b46ae5374eba14c9050.png

  //入队
    @Override
    public void offer(Object x) throws Exception {
        Node p = new Node(x) ;      //初始化新结点
        if (front != null) {         //队列非空
            rear.next = p ;         //指向队尾指向新结点
            rear = p ;              //改变队尾的位置
        }else {
            //队列为空的话,新添加的这个就是队首元素
            front = rear = p ;
        }
    }

算法:出队

60f9932e2bd4470fb1847a6b764ebb76.png

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