Java数据结构学习之栈和队列

一、栈

1.1 概述

Java为什么要有集合类: 临时存储数据。
链表的本质: 对象间通过持有和引用关系互相关联起来。

线性表: 普通线性表, 操作受限线性表(某些操作受到限制 --> 某一个线性表它的增删改操作受到限制) --> 栈 & 队列

1.1.1 线性表的概念

(1)线性表:n个数据元素的有序序列。

①首先,线性表中元素的个数是有限的。
②其次,线性表中元素是有序的。

(2)那这个”序”指的是什么呢?

①除表头和表尾元素外,其它元素都有唯一前驱和唯一后继,其唯一前驱或唯一后继确定了该元素在线性表中的位置。
②因此,线性表中,每个数据元素都有一个确定的位序,这个确定的位序我们称之为索引。 表头元素有唯一后继,无前驱,表尾元素有唯一前驱,无后继。

1.1.2 栈的概念

栈是一种”操作受限”的线性表,体现在只能在一端插入和删除数据,符合FILO的特性。

FILO: 先进后出,
LIFO: 后进先出

1.1.3 栈的应用

线性表和哈希表在以后工作中会最常用。
栈在实际工作中不常用

应用场景:

1.函数调用栈
2.反序字符串: 实现reNumber(str)方法,反转字符串(附代码) 。

public class DemoStack1 {
    public static void main(String[] args) {

        String str = "123456789";
        String reStr = reStr(str);
        System.out.println(reStr);

    }

    // 栈先进后出
    public static String reStr(String str){
        MyArrayStack<Character> stack = new MyArrayStack<>();

        for (int i = 0; i < str.length(); i++) {
            stack.push(str.charAt(i));
        }

        StringBuffer buffer = new StringBuffer();

        // 1 2 3 4 5 6 7 8 9
        while (!stack.isEmpty()){
            Character pop = stack.pop();
            buffer.append(pop);
        }

        return buffer.toString();
    }
}

3.括号匹配问题: 实现judgeBracket(str)方法来判断括号匹配 (附代码)。

public class DemoStack2 {
    public static void main(String[] args) {

        String str = "public class) DemoStack2 {public static void main(String[] args) {}}";

        boolean bool = judgeBracket(str);
        System.out.println(bool);

    }

    public static  boolean judgeBracket(String str){
        MyArrayStack<Character> stack = new MyArrayStack<>();

        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            // 判断c 是left括号, 然后入栈

            if (c == '{'){
                stack.push('}');
            } else if (c == '['){
                stack.push(']');
            }else if (c == '('){
                stack.push(')');
            } else if (c == '}' || c == ')' || c == ']'){
                Character pop = stack.pop();
                if (c != pop){// 不匹配
                    return false;
                }
            }
        }

        return stack.isEmpty();
    }
}

4.编译器利用栈实现表达式求值

5.浏览器的前进后退功能

6. 利用栈实现 DFS: depth-first-search 深度优先遍历(树 图)

编译器利用栈实现表达式求值

中缀表达式: 2 + 3 * 2 给人看的 , 运算符放到中间
前缀表达式: + 2 * 3 2 运算符放到之前
后缀表达式: 2 3 2 * + 运算符放到后面

// 中缀表达式转化为后缀:
// 遍历中缀表达式
// 遇到操作数输出
// 遇到操作符, 出栈, 直到遇到更低优先级的操作符, 操作符入栈
// 遍历完成, 全部弹栈

// 中缀表达式转化为前缀:
// 遍历中缀表达式: 逆序遍历
// 遇到操作数输出: 头插法
// 遇到操作符, 出栈, 只弹出更高优先级的操作符, 操作符入栈
// 遍历完成, 全部弹栈

二、队列

2.1 队列的概念

队列也是一种”操作受限”的线性表,体现在一端插入数据在另一端删除数据,特性是FIFO。

2.2 队列的实现

实现一个集合类
集合类: 数据容器
底层: 数组 or 链表
数据结构表现: 队列

(1)用数组实现一个队列。

/**
 * 用数组实现一个队列
 * 集合类角度: 数据容器
 * 底层: 数组
 * 表示: 队列
 */
public class MyArrayQueue <T> {

    private final int MAX_CAPACITY = Integer.MAX_VALUE - 8;
    private final int INIT_CAPACITY = 16;

    private Object[] objs;
    private int size;
    private int head;// 头的下标
    private int end;// 尾的下标

    public MyArrayQueue(){
        objs = new Object[INIT_CAPACITY];
    }
    public MyArrayQueue(int initCapcity){
        if (initCapcity <= 0 || initCapcity > MAX_CAPACITY) throw new IllegalArgumentException("" + initCapcity);

        objs = new Object[initCapcity];
    }

    public boolean offer(T t){
        // 如果数组满了
        if (size == objs.length){
            int newLen = getLen();
            grow(newLen);
        }

        // 可以添加
        if (isEmpty()){
            // 没有任何元素存储: 新添加的元素就是唯一的元素
            objs[head] = t;
            end = head;
            size++;
            return true;
        } else {
            // 原本存储就有内容

            // 尾后移一位
            end = (end + 1) % objs.length;
            objs[end] = t;
            size++;
            return true;
        }
    }

    private void grow(int newLen) {
        Object[] newArr = new Object[newLen];
        for (int i = 0; i < objs.length; i++) {
            int index = (head + i) % objs.length;

            newArr[i] = objs[index];
        }
        objs = newArr;
        head = 0;
        end = size - 1;
    }

    private int getLen() {
        int oldLen = objs.length;
        int newLen = oldLen << 1;
        // 判断新长度是否溢出
        if (newLen <= 0 || newLen > MAX_CAPACITY){
            newLen = MAX_CAPACITY;
        }
        // 如果新长度和旧长度一样
        if (newLen == oldLen)throw  new RuntimeException("stack can not add");

        return newLen;
    }

    public T poll(){
        if (isEmpty()) throw new RuntimeException("queue is empty");

        if (size == 1){
            // 原队列中只剩一个元素
            T oldValue = (T)objs[head];
            head = 0;
            end = 0;
            size--;
            return oldValue;
        } else {
            // 队列中超过一个元素
            T oldValue = (T)objs[head];
            head = (head + 1) % objs.length;
            size--;
            return oldValue;
        }
    }

    public T peek(){
        if (isEmpty()) throw new RuntimeException("queue is empty");
        return (T)objs[head];
    }

    public int size() {
        return size;
    }

    public boolean isEmpty(){
        return size == 0;
    }
}

(2)用链表实现一个链表。

public class MyLinkedQueue <T> {

    private Node head;// 队头
    private Node end; // 队尾
    private int size;

    // 添加 offer
    // 删除 poll
    // 查看队头元素 peek

    public  boolean offer(T t){

        // 如果原队列为空
        if (isEmpty()){// 原队列空
            // 让头尾都指向这个新加的结点
            head = new Node(t, null);
            end = head;
            size++;
            return true;
        }

        // 原队列不空
        // 把这个元素添加到队尾
        end.next = new Node(t, null);
        end = end.next;// end后移
        size++;
        return true;
    }

    public T poll(){
        if (isEmpty()) throw  new RuntimeException("queue is empty");

        if (size == 1){
            // 代表着, 链表中只有一个元素
            T oldVlaue = head.value;
            head = null;
            end = null;
            size--;
            return  oldVlaue;
        }else {
            T oldVlaue = head.value;
            head = head.next;
            size--;
            return oldVlaue;
        }
    }

    public T peek(){
        if (isEmpty()) throw  new RuntimeException("queue is empty");
        return head.value;
    }

    public boolean isEmpty(){
        return size == 0;
    }
    public int size(){
        return size;
    }

    class Node{
        T value;
        Node next;

        public Node(T value, Node next) {
            this.value = value;
            this.next = next;
        }
    }
}

2.3 队列的应用

(1)队列更不常用(自己写代码使用不常用):

(2)常见, 很多jdk源码, 中间件的源码上 很多地方使用了队列

Eg:

①生产者消费者问题

生产者 – 消费者
生产者: 厨师
消费者: 吃面包的人
桌子: 放面包的地方

②线程池

线程池: 任务
生产者: 产生任务
消费者: 线程
桌子: 队列

③生态环境:

第三方轮子: 要看懂
Maven

④消息队列和缓存。

(3)普通队列的应用场景是很有限的,一般在工程中用到的是阻塞队列。

①阻塞队列(有一个队列, 大小一定):常用于生产者-消费者模型中。
当队列满的时候,入队列就阻塞。
当队列空的时候,出队列就阻塞。

②利用队列实现 BFS:breadth first search 广度优先搜索/ 遍历 ()

到此这篇关于Java数据结构学习之栈和队列的文章就介绍到这了,更多相关Java栈和队列内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java实现栈和队列面试题

    面试的时候,栈和队列经常会成对出现来考察.本文包含栈和队列的如下考试内容: (1)栈的创建 (2)队列的创建 (3)两个栈实现一个队列 (4)两个队列实现一个栈 (5)设计含最小函数min()的栈,要求min.push.pop.的时间复杂度都是O(1) (6)判断栈的push和pop序列是否一致 1.栈的创建: 我们接下来通过链表的形式来创建栈,方便扩充. 代码实现: public class Stack { public Node head; public Node current; //方法

  • Java特性队列和栈的堵塞原理解析

    做消息通信,消息会不断从网络流中取得,而后台也有线程不断消费.本来我一直是使用一些线程安全标识或方法来控制,后来在网上找到一些java新特性,里面包含了可以用到的堆栈使用,而且是堵塞的,这样至少可以保证一些安全性. 对于堆: BlockingQueue 不接受 null 元素.试图 add.put 或 offer 一个 null 元素时,某些实现会抛出 NullPointerException.null 被用作指示 poll 操作失败的警戒值. BlockingQueue 可以是限定容量的.它在

  • Java模拟栈和队列数据结构的基本示例讲解

    栈和队列: 一般是作为程序员的工具,用于辅助构思算法,生命周期较短,运行时才被创建: 访问受限,在特定时刻,只有一个数据可被读取或删除: 是一种抽象的结构,内部的实现机制,对用户不可见,比如用数组.链表来实现栈. 模拟栈结构 同时,只允许一个数据被访问,后进先出 对于入栈和出栈的时间复杂度都为O(1),即不依赖栈内数据项的个数,操作比较快 例,使用数组作为栈的存储结构 public class StackS<T> { private int max; private T[] ary; priv

  • java 数据结构中栈和队列的实例详解

    java 数据结构中栈和队列的实例详解 栈和队列是两种重要的线性数据结构,都是在一个特定的范围的存储单元中的存储数据.与线性表相比,它们的插入和删除操作收到更多的约束和限定,又被称为限定性的线性表结构.栈是先进后出FILO,队列是先进先出FIFO,但是有的数据结构按照一定的条件排队数据的队列,这时候的队列属于特殊队列,不一定按照上面的原则. 实现栈:采用数组和链表两种方法来实现栈 链表方法: package com.cl.content01; /* * 使用链表来实现栈 */ public cl

  • java 数据结构之栈与队列

    java 数据结构之栈与队列 一:对列 队列是一种先进先出的数据结构 实现代码: package Queue; /* * 使用java构建队列,并模拟实现队列的入队和出对方法 */ public class Queue { //队列类 private int maxSize; //定义队列的长度 private int[] arrQueue; //队列 private int rear; //定义队列的尾指针 private int front; //定义队列的头指针 private int e

  • 如何使用两个栈实现队列Java

    这篇文章主要介绍了如何使用两个栈实现队列Java,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 题目 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 题解 描述 栈的特性是先进后出,队列的特点是先进先出,当数字依次入栈1后,依次出栈1并且压入栈2后,然后再出栈的顺序与进入栈1的顺序是一致的. 因此,进入队列通过压入栈1实现,弹出队列通过弹出栈2的栈顶元素实现,在弹出元素时需要保证当前栈弹出元素的顺序和队列弹

  • Java编程用两个栈实现队列代码分享

    题目:用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 经典题,不多说,直接上代码 import java.util.Stack; public class Solution { Stack<Integer> stack1 = new Stack<Integer>(); Stack<Integer> stack2 = new Stack<Integer>(); public void push(int node) { st

  • Java数据结构之链表、栈、队列、树的实现方法示例

    本文实例讲述了Java数据结构之链表.栈.队列.树的实现方法.分享给大家供大家参考,具体如下: 最近无意中翻到一本书,闲来无事写几行代码,实现几种常用的数据结构,以备后查. 一.线性表(链表) 1.节点定义 /**链表节点定义 * @author colonel * */ class Node { public int data; Node next=null; public Node(int data){ this.data=data; } } 2.链表操作类 /**链表操作类 * @auth

  • java中栈和队列的实现和API的用法(详解)

    在java中要实现栈和队列,需要用到java集合的相关知识,特别是Stack.LinkedList等相关集合类型. 一.栈的实现 栈的实现,有两个方法:一个是用java本身的集合类型Stack类型:另一个是借用LinkedList来间接实现Stack. 1.Stack实现 直接用Stack来实现非常方便,常用的api函数如下: boolean        isEmpty() // 判断当前栈是否为空 synchronized E        peek() //获得当前栈顶元素 synchro

  • Java数据结构学习之栈和队列

    一.栈 1.1 概述 Java为什么要有集合类: 临时存储数据. 链表的本质: 对象间通过持有和引用关系互相关联起来. 线性表: 普通线性表, 操作受限线性表(某些操作受到限制 --> 某一个线性表它的增删改操作受到限制) --> 栈 & 队列 1.1.1 线性表的概念 (1)线性表:n个数据元素的有序序列. ①首先,线性表中元素的个数是有限的. ②其次,线性表中元素是有序的. (2)那这个"序"指的是什么呢? ①除表头和表尾元素外,其它元素都有唯一前驱和唯一后继,

  • Java数据结构学习之树

    一.树 1.1 概念 与线性表表示的一一对应的线性关系不同,树表示的是数据元素之间更为复杂的非线性关系. 直观来看,树是以分支关系定义的层次结构. 树在客观世界中广泛存在,如人类社会的族谱和各种社会组织机构都可以用树的形象来表示. 简单来说,树表示的是1对多的关系. 定义(逻辑结构): 树(Tree)是n( n>=0 )个结点的有限集合,没有结点的树称为空树,在任意一颗非空树中: 有且仅有一个特定的称为根(root)的结点 . 当n>1的时,其余结点可分为 m( m>0 ) 个互不相交的

  • Java数据结构学习之二叉树

    1 背景知识:树(Tree) 在之前的笔记中,我们介绍的链表.栈.队列.数组和字符串都是以线性结构来组织数据的.本篇笔记要介绍的树采用的是树状结构,这是一种非线性的数据组织形式. 树结构由节点和边构成,且不存在环.我们曾在线性表型的数据结构中介绍过循环链表和循环队列,这两种数据结构使得存储容器中的元素形成一个闭环,具体可参看"数据结构学习笔记"系列的相关博文,链接贴在下面: 链表:https://www.jb51.net/article/215278.htm 队列:https://ww

  • Java分布式学习之Kafka消息队列

    目录 介绍 Kafka核心相关名称 kafka集群安装 kafka使用 kafka文件存储 Springboot整合kafka 介绍 Apache Kafka 是分布式发布-订阅消息系统,在 kafka官网上对 kafka 的定义:一个分布式发布-订阅消息传递系统. 它最初由LinkedIn公司开发,Linkedin于2010年贡献给了Apache基金会并成为顶级开源项目.Kafka是一种快速.可扩展的.设计内在就是分布式的,分区的和可复制的提交日志服务. 注意:Kafka并没有遵循JMS规范(

  • C语言数据结构进阶之栈和队列的实现

    目录 栈的实现: 一.栈的概念和性质 二.栈的实现思路 三.栈的相关变量内存布局图 四.栈的初始化和销毁 五.栈的接口实现: 1.入栈 2.出栈 3.获取栈顶的数据 4.获取栈的元素个数 5.判断栈是否为空 队列的实现: 一.队列的概念和性质 二.队列的实现思路 三.队列相关变量的内存布局图 四.队列的初始化和销毁 五.队列的接口实现: 1. 入数据 2.出数据 3.取队头数据 4.取队尾数据 5.获取队列元素个数 6.判断队列是否为空 总结 栈的实现: 一.栈的概念和性质 栈(stack)又名

  • Java数据结构与算法之循环队列的实现

    目录 概述 循环队列 循环队列实现 改变队列大小 enqueue 方法 dequeue 方法 main 完整代码  概述 从今天开始, 小白我将带大家开启 Jave 数据结构 & 算法的新篇章. 循环队列 循环队列 (Circular Queue) 是一种特殊的队列. 循环队列解决了队列出队时需要将所有数据前移一位 (复杂度为 O(n)) 的问题. 循环队列的底层依然是数组, 不过增加了指向头和尾的指针. 循环队列实现 判断队列是否为空: 当头指针 Q.front == 尾指针 Q.rear,

  • C++数据结构深入探究栈与队列

    目录 1. 栈 1.1 栈的概念 1.2 栈的实现 2. 队列 2.1 队列的概念 2.2 队列的实现 3. 栈和队列面试题 3.1 括号匹配问题 3.2用队列实现栈 3.3 用栈实现队列 3.4 设计循环队列 1. 栈 1.1 栈的概念 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作.进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底.栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则. 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶.

  • java数据结构与算法数组模拟队列示例详解

    目录 一.什么是队列 二.用数组来模拟队列 一.什么是队列 队列是一个有序列表,可以用数组或者链表来实现. 遵循先入先出的原则,即:先存入队列的数据,要先取出.后存入的的数据,后取出. 看一张队列的模拟图,1,2,3表示同一个队列Queue.在队列中有2个指针,front表示队首,rear表示队尾. 图1中表示队列里还没有数据,所以front跟rear初始化都是-1. 当图2中有数据进行存入的时候,front没变,而rear则随着数据的增多而改变.存入了4个数据,于是rear=3. 再看图3,f

  • JavaScript数据结构学习之数组、栈与队列

    前言 数据结构就是关系,没错,就是数据元素相互之间存在的一种或多种特定关系的集合. 常用的数据结构有: 数组,队列(queue),堆(heap),栈(stack),链表(linked list ),树(tree),图(graph)和散列表(hash) 本文主要介绍的是数组.栈与队列,下面来一起看看详细的介绍吧. 一.数组 数组是平时使用最常用的数据结构,在JavaScript中数组是动态的分配大小,在这里我不会介绍JavaScript里面数组的所有的方法,而是针对数据结构这个方向谈谈所用到的方法

随机推荐