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

 更新时间:2022年02月14日 14:54:58   作者:Word码鸭  
这篇文章主要介绍了Java数据结构中的栈与队列,在Java的时候,对于栈与队列的应用需要熟练的掌握,这样才能够确保Java学习时候能够有扎实的基础能力。本文小编就来详细说说Java中的栈与队列,需要的朋友可以参考一下

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

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

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

栈(stack)

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

20191212190125865.gif (1920×1080)

20191212204731172.gif (1920×1080)

栈支持的三个核心操作:

  • 入栈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 栈和基础队列内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Kotlin基本类型自动装箱出现问题解决办法

    Kotlin基本类型自动装箱出现问题解决办法

    这篇文章主要介绍了Kotlin基本类型自动装箱出现问题解决办法的相关资料,希望通过本文能帮助到大家,让大家遇到这样的问题顺利解决,需要的朋友可以参考下
    2017-10-10
  • 超好用的Java工具类库Hutool用法详解

    超好用的Java工具类库Hutool用法详解

    Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,下面就跟随小编一起来学习一下Hutool的具体用法吧
    2023-09-09
  • struts2中simple主题下<s:fieldError>标签默认样式的移除方法

    struts2中simple主题下<s:fieldError>标签默认样式的移除方法

    这篇文章主要给大家介绍了关于struts2中simple主题下<s:fieldError>标签默认样式的移除方法,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧
    2018-10-10
  • Java求出任意数字的各个位数之和方式

    Java求出任意数字的各个位数之和方式

    这篇文章主要介绍了Java求出任意数字的各个位数之和方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • java保证对象在内存中唯一性的实现方法

    java保证对象在内存中唯一性的实现方法

    这篇文章主要介绍了java如何保证对象在内存中的唯一性,如果创建多个对象的话,可能会引发出各种各样的问题,这时,就需要我们保证这个对象在内存中的唯一性,需要的朋友可以参考下
    2019-06-06
  • MyBatis插入Insert、InsertSelective的区别及使用心得

    MyBatis插入Insert、InsertSelective的区别及使用心得

    这篇文章主要介绍了MyBatis插入Insert、InsertSelective的区别及使用心得,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • Java分布式学习之Kafka消息队列

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

    Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据
    2022-07-07
  • SpringBoot实现登录校验(JWT令牌)

    SpringBoot实现登录校验(JWT令牌)

    JWT全称为JSON Web Token,是一种用于身份验证的开放标准,本文主要介绍了SpringBoot实现登录校验(JWT令牌),具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • java的java.security.egd源码解读

    java的java.security.egd源码解读

    这篇文章主要为大家介绍了java的java.security.egd源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • jvm双亲委派 vs 破坏双亲委派理解加载器的权责分配

    jvm双亲委派 vs 破坏双亲委派理解加载器的权责分配

    这篇文章主要为大家介绍了jvm双亲委派 vs 破坏双亲委派对比来理解加载器的权责分配,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10

最新评论