Java栈和基础队列的实现详解

目录
  • 栈(stack)
    • 栈支持的三个核心操作:
    • 栈的常见实际应用:
    • 栈的实现
  • 队列
    • 无论是哪种队列,都必须支持三个核心操作:
    • 基础队列的实现

栈和队列:都是线性表,都是基于List基础上的实现

线性表:数组,链表,字符串,栈,队列

元素按照一条“直线”排列,线性表这个结构中,一次添加单个元素

栈(stack)

一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

栈支持的三个核心操作:

  • 入栈push
  • 出栈pop
  • 返回栈顶元素peek

栈的常见实际应用:

  • 无处不在的撤销操作undo,一般任意的编辑器都使用 ctrl + z 操作,其实本质就是每次操作一次 ctrl + z 就是一次栈的pop
  • 浏览器的前进后退,浏览器维护了一个栈结构A->B->C,此时页面停留在C,想要回到页面B,点击后退键头就相当于将C出栈,此时的栈顶就是B
  • 在开发程序中的“调用栈”操作系统栈底层就是栈的实现

栈的实现

栈是一种线性表,所以实现它即可使用数组,也可以使用链表

  • 基于数组实现的栈—顺序栈(栈顶实际就是数组尾部,在数组尾部添加和删除)
  • 基于链表实现的栈—链式栈(链表的头插和尾插)

在数组尾部进行删除和插入的时间复杂度为O(1),所以用数组实现栈是我们的首选

实现代码:

//基于数组实现的栈
public class MyStack<E> {
    private int size;//数组长度
    //实际存储数据的动态数组
    private List<E> data = new ArrayList<>();

    //入栈,默认尾插
    public void push(E val){
        data.add(val);
        size ++;
    }

    //弹出栈顶元素,返回栈顶的值
    public E pop(){
        if(isEmpty()){
            //栈为空
            throw new NoSuchElementException("stack is empty!cannot pop!");
        }
        //删元素
       E val =  data.remove(size-1);
        size--;
        return val;
        //上面三句等同于return data.remove(size-1);
    }

    //返回栈顶元素,但不出栈
    public E peek(){
        if(isEmpty()){
            throw new NoSuchElementException("stack is empty!cannot peek");
        }
        return data.get(size-1);
    }

    // 判断当前栈是否为空
    public boolean isEmpty() {
        return size == 0;
    }
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < size; i++) {
            sb.append(data.get(i));
            if (i != size - 1) {
                // 此时还没到栈顶,还没到数组末尾
                sb.append(", ");
            }
        }
        sb.append("] top");
        return sb.toString();
    }
}

//--------------------------
//测试类·
public class StackTest {
    public static void main(String[] args) {
        MyStack<Integer> myStack = new MyStack<>();
        myStack.push(1);
        myStack.push(3);
        myStack.push(5);
        System.out.println(myStack);
        System.out.println(myStack.pop());//删除栈顶
        System.out.println(myStack.peek());//输出栈顶,此时栈顶为3
        System.out.println(myStack.isEmpty());
    }
}

//输出结果:
[1, 3, 5] top
5
3
false

队列

只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列遵循先进先出FIFO(First In First Out)的原则 :进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头

其实队列的定义很简单,就相当于我们现实生活的排队购物,先排队的人先结账,也就先离开

队列的子类比栈要复杂一些,它有:

  • 基础队列—FIFO
  • 基于优先级的队列—按照优先级大小出队
  • 循环队列—基于数组实现的
  • 双端队列

无论是哪种队列,都必须支持三个核心操作:

  • 入队—offer
  • 出队—poll
  • 返回队首元素—peek

基础队列的实现

  • 基于数组实现的队列—顺序队列
  • 基于链表实现的队列—链式队列

由于队列是从队尾插入,队首出队,而在数组头部删除的时间复杂度为O(n),此时我们用链表会更好一些。而且无论实现哪种队列都需要覆写三个基本操作,因此我们将队列设计为接口

实现代码:

public interface Queue<E> {
    // 入队
    void offer(E val);
    // 出队
    E poll();
    // 返回队首元素
    E peek();
    // 判断队列是否为空
    boolean isEmpty();
}

 //基于链表实现的基础队列
public class MyQueue<E> implements Queue<E> {
    // 链表的每个节点
    // ------------------------------
    //内部类
    private class Node {
        E val;
        Node next;
        public Node(E val) {
            this.val = val;
        }
    }
    // ------------------------------
    // 当前队列中的元素个数
    private int size;
    // 队首
    private Node head;
    // 队尾
    private Node tail;
    @Override
    public void offer(E val) {
        Node node = new Node(val);
        if (head == null) {
            // 此时链表为空
            head = tail = node;
        }else {
            tail.next = node;
            tail = node;
        }
        size ++;
    }

    @Override
    public E poll() {
        if (isEmpty()) {
            throw new NoSuchElementException("queue is empty!cannot poll!");
        }
        E val = head.val;
        Node node = head;
        head = head.next;
        // 将原来头节点脱钩
        node.next = null;
        size --;
        return val;
    }

    @Override
    public E peek() {
        if (isEmpty()) {
            throw new NoSuchElementException("queue is empty!cannot peek!");
        }
        return head.val;
    }

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

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("front [");
        // 链表的遍历
        for (Node x = head;x != null;x = x.next) {
            sb.append(x.val);
            if (x.next != null) {
                // 还没走到链表尾部
                sb.append(", ");
            }
        }
        sb.append("]");
        return sb.toString();
    }
}

//测试类
public class QueueTest {
    public static void main(String[] args) {
        Queue<Integer> queue = new MyQueue<>();
        queue.offer(1);
        queue.offer(3);
        queue.offer(5);
        System.out.println(queue);
    }
}

作为初学者,我们不能小瞧任何简单的数据结构与算法,基础的数据结构往往作为高阶数据结构的一部分来应用,万丈高楼平地起,平时要多加练习,我们一起加油!

到此这篇关于Java栈和基础队列的实现详解的文章就介绍到这了,更多相关Java 栈和基础队列内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java数据结构关于栈的实例应用

    此文章介绍关于顺序栈,链式栈的实例操作,括号匹配,表达式求值(后缀表达式) 1.声明一个栈接口SStack package ch05; public interface SStack <T>{ boolean isEmpty(); // 判断栈是否为空 void push(T x); // 元素x入栈 T pop(); // 出栈,返回栈顶元素 T peek(); // 返回栈顶元素,但不出栈 }  2. 定义顺序栈类SeqStack<T>,包括数据元素的对象数组和栈顶元素下标两个

  • 简单谈谈Java中的栈和堆

    人们常说堆栈堆栈,堆和栈是内存中两处不一样的地方,什么样的数据存在栈,又是什么样的数据存在堆中? 这里浅谈Java中的栈和堆 首先,将结论写在前面,后面再用例子加以验证. Java的栈中存储以下类型数据,栈对应的英文单词是Stack 基本类型 引用类型变量 方法 栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享.但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性. 栈中主要存放一些基本类型的变量(int, short, long, byte, float, double, b

  • Java 栈和队列的相互转换详解

    目录 用栈实现队列-力扣232题 用队列实现栈-力扣225题  1. 双队列实现栈 2.一个队列实现栈 栈和队列的本质是相同的,都只能在线性表的一端进行插入和删除.因此,栈和队列可以相互转换. 用栈实现队列-力扣232题 题目要求:仅使用两个栈实现先入先出队列.队列应当支持一般队列支持的所有操作 使用双栈来实现队列,我们就可以让一个栈储存具体元素,另一个栈做辅助  上图可以看到,新元素进栈时,要确保该栈为空.进入栈的元素按顺序存到辅助栈中,等新元素进入栈之后,再将辅助栈中的元素按顺序出到该栈中.

  • Java数据结构之栈的详解

    目录 栈的抽象定义 顺序栈-----------使用数组表示栈空间 总结 栈是先进后出的特殊线性表,只允许在表的末端进行插入和删除,后面将介绍两种实现栈的方式,分别是基于数组的实现.基于链表的实现. 栈的抽象定义 class Mystack { public: Mystack() {} virtual void push(int &x) = 0; virtual bool pop(int &x) = 0; virtual bool Top(int &x) const = 0; vi

  • Java深入了解数据结构之栈与队列的详解

    目录 一,栈 1,概念 2,栈的操作 3,栈的实现 ①入栈 ②出栈 ③获取栈顶元素 ④判断栈是否为空 4,实现mystack 二,队列 1,概念 2,队列的实现 ①入队 ②出队 ③获取队首元素 3,实现myqueue 一,栈 1,概念 在我们软件应用 ,栈这种后进先出数据结构的应用是非常普遍的.比如你用浏 览器上网时不管什么浏览器都有 个"后退"键,你点击后可以接访问顺序的逆序加载浏览过的网页. 很多类似的软件,比如 Word Photoshop 等文档或图像编 软件中 都有撤销 )的

  • Java数据结构之栈与队列实例详解

    目录 一,栈 1,概念 2,栈的操作 3,栈的实现  4,实现mystack 二,队列 1,概念  2,队列的实现  3,实现myqueue 栈.队列与数组的区别? 总结 一,栈 1,概念 在我们软件应用 ,栈这种后进先出数据结构的应用是非常普遍的.比如你用浏 览器上网时不管什么浏览器都有 个"后退"键,你点击后可以接访问顺序的逆序加载浏览过的网页.   很多类似的软件,比如 Word Photoshop 等文档或图像编 软件中 都有撤销 )的操作,也是用栈这种方式来实现的,当然不同的

  • 带你了解Java数据结构和算法之栈

    目录 1.栈的基本概念 2.Java模拟简单的顺序栈实现 3.增强功能版栈 4.利用栈实现字符串逆序 5.利用栈判断分隔符是否匹配 6.总结 1.栈的基本概念 栈(英语:stack)又称为堆栈或堆叠,栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表.它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来).栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针. 栈是允许在同一端进行插入和删除操

  • Java 数据结构与算法系列精讲之栈

    目录 概述 栈 栈实现 push方法 pop方法 main 完整代码 概述 从今天开始, 小白我将带大家开启 Jave 数据结构 & 算法的新篇章. 栈 栈 (Stack) 是一种运算受限的线性表, 遵循先进后出的原则 (Last-In-First-Out). 举个例子, 当我们灌调料的时候, 后灌进去的调料会先被使用. 栈只能在表尾部进行插入和删除的操作. 开口的一端被称为栈顶, 另一端则被称为栈底. 如图: 栈实现 push 方法 栈 (Stack) 的 push 方法, 把项压入栈顶部.

  • Java栈和基础队列的实现详解

    目录 栈(stack) 栈支持的三个核心操作: 栈的常见实际应用: 栈的实现 队列 无论是哪种队列,都必须支持三个核心操作: 基础队列的实现 栈和队列:都是线性表,都是基于List基础上的实现 线性表:数组,链表,字符串,栈,队列 元素按照一条“直线”排列,线性表这个结构中,一次添加单个元素 栈(stack) 一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作.进行数据插入和删除操作的一端称为栈顶,另一端称为栈底.栈中的数据元素遵守后进先出LIFO(Last In First Out)

  • Java数据结构之优先级队列(PriorityQueue)用法详解

    目录 概念 PriorityQueue的使用 小试牛刀(最小k个数) 堆的介绍 优先级队列的模拟实现 Top-k问题 概念 优先级队列是一种先进先出(FIFO)的数据结构,与队列不同的是,操作的数据带有优先级,通俗的讲就是可以比较大小,在出队列的时候往往需要优先级最高或者最低的元素先出队列,这种数据结构就是优先级队列(PriorityQueue) PriorityQueue的使用 构造方法 这里只介绍三种常用的构造方法 构造方法 说明 PriorityQueue() 不带参数,默认容量为11 P

  • Java数据结构之优先级队列(堆)图文详解

    目录 一.堆的概念 二.向下调整 1.建初堆 2.建堆 三.优先级队列 1.什么是优先队列? 2.入队列 3.出队列 4.返回队首元素 5.堆的其他TopK问题 总结: 总结 一.堆的概念 堆的定义:n个元素的序列{k1 , k2 , … , kn}称之为堆,当且仅当满足以下条件时: (1)ki >= k2i 且 ki >= k(2i+1) ——大根堆 (2) ki <= k2i 且 ki <= k(2i+1) ——小根堆 简单来说: 堆是具有以下性质的完全二叉树:(1)每个结点的

  • Java中一些基础概念的使用详解

    类的初始化顺序 在Java中,类里面可能包含:静态变量,静态初始化块,成员变量,初始化块,构造函数.在类之间可能存在着继承关系,那么当我们实例化一个对象时,上述各部分的加载顺序是怎样的? 首先来看代码: 复制代码 代码如下: class Parent {     public static StaticVarible staticVarible= new StaticVarible("父类-静态变量1");         public StaticVarible instVaribl

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

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

  • Java基础之集合框架详解

    一.前言 本节学习到的内容有以下5类,不分先后顺序: 集合Collection体系结构 List子类 与集合结合使用的迭代器对象 集合与数组的区别? 常见的一般数据结构整理 二.集合的由来? Collection List ArrayList Vector LinkedList Set hashSet treeSet 在集合没有出现之前,使用对象数组来存储对象,但是,对象数组的长度一旦确定,则不可以发生变化,所以我们希望存在一个容器就像StringBuffer一样存储字符串,同时依据传入的值的个

  • Java基础之代码死循环详解

    一.前言 代码死循环这个话题,个人觉得还是挺有趣的.因为只要是开发人员,必定会踩过这个坑.如果真的没踩过,只能说明你代码写少了,或者是真正的大神. 尽管很多时候,我们在极力避免这类问题的发生,但很多时候,死循环却悄咪咪的来了,坑你于无形之中.我敢保证,如果你读完这篇文章,一定会对代码死循环有一些新的认识,学到一些非常实用的经验,少走一些弯路. 二.死循环的危害 我们先来一起了解一下,代码死循环到底有哪些危害? 程序进入假死状态, 当某个请求导致的死循环,该请求将会在很大的一段时间内,都无法获取接

  • java实现队列数据结构代码详解

    什么是队列结构 一种线性结构,具有特殊的运算法则[只能在一端(队头)删除,在另一端(队尾)插入]. 分类: 顺序队列结构 链式队列结构 基本操作: 入队列 出队列 给出一些应用队列的场景 1):当作业被送到打印机的时候,就可以按到达的顺序排起来,因此每一份作业是队列的节点. 2):售票口的人买票的顺序的按照先来先买的顺序售票. 3):当所有的终端被占用,由于资源有限,来访请求需要放在一个队列中等候. 队列是先进先出的! 我们设置一个叫做LinkQueue<T>的泛型集合类,该类里面有 Node

  • Java数据结构之图的基础概念和数据模型详解

    目录 图的实际应用 图的定义及分类 图的相关术语 图的存储结构 邻接矩阵 邻接表 图的实现 图的API设计 代码实现 图的实际应用 在现实生活中,有许多应用场景会包含很多点以及点点之间的连接,而这些应用场景我们都可以用即将要学习的图这种数据结构去解决. 地图: 我们生活中经常使用的地图,基本上是由城市以及连接城市的道路组成,如果我们把城市看做是一个一个的点,把道路看做是一条一条的连接,那么地图就是我们将要学习的图这种数据结构. 图的定义及分类 定义: 图是由一组顶点和一组能够将两个顶点相连的边组

  • Java基础之关键字final详解

    Java-关键字:final 1 .final可以用来修饰的结构: 类.方法.变量 2.final 用来修饰一个类: 此类不能被其他类所继承 比如:String类.System类.StringBuffer类 3.final 用来修饰方法: 表明此方法不可以被重写 比如:Object类中getClass(); 4.final 用来修饰变量,此时的"变量"就称为是一个常量 4.1 final修饰属性: 可以考虑赋值的位置有:显示初始化.代码块中初始化.构造器中初始化 4.2 final修饰

随机推荐