Java 数据结构之栈、队列(头歌平台,详细注释)

这篇具有很好参考价值的文章主要介绍了Java 数据结构之栈、队列(头歌平台,详细注释)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

第1关:实现基于数组的

任务描述

相关知识

栈的数组表示

Java 泛型简介

泛型方法

泛型类应用场景示例

代码: 

第2关:实现基于链表的栈

任务描述

相关知识

栈的链式存储

入栈

出栈

代码: 

第3关:基于数组的队列

任务描述

相关知识

队列

队列的数组实现

循环队列

代码: 

第4关:基于链表的队列

任务描述

相关知识

链式队列

入队操作

代码: 


第1关:实现基于数组的

任务描述

在日常生活中,栈是常见的事物。餐厅里的一叠盘子、弹夹都是栈的例子。如弹夹,最先弹出的子弹是最后压入的那颗。

栈可以用数组实现,也可以用链表实现。

本关任务:基于数组,利用Java中泛型实现一个栈,并具有基本的入栈、出栈功能。

相关知识

栈,是一种运算受限的线性表;仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。对栈的基本操作有push(入栈)和pop(出栈),前者是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;后者是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

一个栈的示意图:

头歌java 数据结构之栈、队列 第1关:实现基于数组的栈,java头歌平台,java,数据结构,开发语言

下面是1 2 3入栈出栈的示意图:

头歌java 数据结构之栈、队列 第1关:实现基于数组的栈,java头歌平台,java,数据结构,开发语言

用数组表示线性表的相关知识可以参考之前的实训。

栈的数组表示

我们可以用一个数组S[1...n]来实现一个最多容纳n个元素的栈。该数组有一个top属性,指向最新插入的元素。栈中包含的元素为S[1...top],其中S[1]是栈底元素,S[top]是栈顶元素。

下图是栈的数组实现的一个实例,top指向的是栈顶元素的下标:

头歌java 数据结构之栈、队列 第1关:实现基于数组的栈,java头歌平台,java,数据结构,开发语言

(a)S内有4个元素。栈顶元素为9(b)调用push(17)push(3)后的栈S(c)调用pop()并返回栈顶元素3的栈S。虽然3仍然在数组里,但它已经不在栈内了,此时栈顶的元素是17

Java 泛型简介

Java 泛型是JDK 5中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。 泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

泛型方法

假定我们有这样一个需求:写一个排序方法,能够对整型数组、字符串数组甚至其他任何类型的数组进行排序,该如何实现?答案是使用Java泛型。 使用Java泛型的概念,我们可以写一个泛型方法来对一个对象数组排序。然后,调用该泛型方法来对整型数组、浮点数数组、字符串数组等进行排序。

下面是定义泛型方法的规则:

  • 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的<E>);
  • 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符;
  • 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符;
  • 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(如int,double,char的等)。

泛型方法实例:

public class GenericMethodTest
{
   // 泛型方法 printArray                         
   public static < E > void printArray( E[] inputArray )
   {
      // 输出数组元素            
         for ( E element : inputArray ){        
            System.out.printf( "%s ", element );
         }
         System.out.println();
    }
 
    public static void main( String args[] )
    {
        // 创建不同类型数组: Integer, Double 和 Cha\fracter
        Integer[] intArray = { 1, 2, 3, 4, 5 };
        Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
        Cha\fracter[] charArray = { 'H', 'E', 'L', 'L', 'O' };
 
        System.out.println( "整型数组元素为:" );
        printArray( intArray  ); // 传递一个整型数组
 
        System.out.println( "\n双精度型数组元素为:" );
        printArray( doubleArray ); // 传递一个双精度型数组
 
        System.out.println( "\n字符型数组元素为:" );
        printArray( charArray ); // 传递一个字符型数组
    } 
}
泛型类应用场景示例

假设要对一个盒子编程,我们需要定义一个Box类,具体定义如下:

public class Box {
    private String obj;
    public void set(String obj) { this.obj = obj; }
    public String get() { return obj; }
}

这是最常见的做法,这样做的一个坏处是Box中的obj只能是String类型,如果我们今后需要把obj改为Integer等其他类型的元素,还必须要另外重写一个Box,代码得不到复用,使用泛型可以很好的解决这个问题。

public class Box<T> {
    // T stands for "Type"
    private T obj;
    public void set(T obj) { this.obj = obj; }
    public T get() { return obj; }
}

这样我们的Box类便可以得到复用,我们可以将T替换成任何我们想要的类型:

Box<Integer> integerBox = new Box<Integer>();
Box<Double> doubleBox = new Box<Double>();
Box<String> stringBox = new Box<String>();
代码: 
package step1;

import java.util.NoSuchElementException;

/**
 * Created by sykus on 2018/1/26.
 */
public class MyStack<T> {
    private T[] S;
    private int top;//栈顶元素下标,初始为-1

    public MyStack() {
        this(1);
    }

    public MyStack(int capacity) {
        S = (T[]) new Object[capacity];
        top = -1;
    }


    /**
     * 入栈操作,把item压入栈中
     *
     * @param item
     */
    public void push(T item) {

        int len = S.length;
        if (top == len - 1) {
            resize(2 * len);
        }
        /********** Begin *********/
        S[++top]=item;//top栈顶由-1开始,先自增,再储存元素

        /********** End *********/
    }


    /**
     * 返回栈顶元素并从栈中移除
     *
     * @return
     */
    public T pop() {
        if (isEmpty()) {
            throw new NoSuchElementException("栈为空!");
        }

        /********** Begin *********/

        return S[top--];//直接返回top位置的元素,并减,因为栈是先进后出

        /********** End *********/
    }

    /**
     * 判断栈是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        if (top < 0)
            return true;
        else
            return false;
    }

    /**
     * 动态扩展数组大小
     *
     * @param capacity
     */
    private void resize(int capacity) {
        assert capacity > top;
        T[] tmp = (T[]) new Object[capacity];
        for (int i = 0; i <= top; i++) {
            tmp[i] = S[i];
        }
        S = tmp;
    }
}

预期输入:

  1. to be or not to - be - - that - - - is

预期输出:

  1. to be not that or be

第2关:实现基于链表的栈

任务描述

上一关,我们介绍了Java泛型,并用数组实现了栈,这一关我们将基于链表实现栈。

本关任务:基于单链表实现一个栈,并具备入栈、出栈功能。

相关知识
栈的链式存储

栈的链式存储结构称为链栈,是运算受限的单链表,其插入和删除操作只能在表头进行,如下图:

头歌java 数据结构之栈、队列 第1关:实现基于数组的栈,java头歌平台,java,数据结构,开发语言

入栈

基于单链表实现的栈,入栈就是插入一个新结点,这里在头结点后插入新结点:

头歌java 数据结构之栈、队列 第1关:实现基于数组的栈,java头歌平台,java,数据结构,开发语言

上图中,首先让新结点的next指向原来的栈顶元素head.next,保持对整个链表的引用,再把head.next指向新结点。

出栈

同样,出栈就是删除第一个结点:

头歌java 数据结构之栈、队列 第1关:实现基于数组的栈,java头歌平台,java,数据结构,开发语言

删除头结点,可以直接把head.next指向head.next.next

此外,这里同样用了泛型,相关Java泛型知识请参考上一关。

代码: 
package step2;

import java.util.NoSuchElementException;

/**
 * Created by sykus on 2017/12/29.
 */
public class MyStack<E> {

    private Node<E> head;//头结点
    private Node<E> top;//栈顶
    private int size;//栈中元素个数

    public MyStack() {
        head = new Node<E>();
        head.next = null;
        top = null;//栈顶初始化为null
        size = 0;
    }

    /**
     * 把item压入栈中
     *
     * @param item
     */
    public void push(E item) {
        /********** Begin *********/
        Node newNode=new Node();//创建一个新的结点
        newNode.item=item;//将值存入新结点
        newNode.next=head.next;//确定新结点指向(头的当前结点)
        head.next=newNode;//将头的指向改为新结点
        top=newNode;//栈顶指向新结点
        ++size;//元素个数+1
        /********** End *********/
    }

    /**
     * 返回它栈顶元素并删除
     */
    public E pop() {
        if (isEmpty())
            throw new NoSuchElementException("栈为空!");

        /********** Begin *********/
        Node<E> t=top;//保存删除元素,这里我把<E>删了运行不了
        top=top.next;//栈顶指向栈的下一个元素,因为栈顶需要被删除
        head.next=top;//头指向栈顶,此时栈顶已经改为下一个元素
        --size;//元素个数-1
        return t.item;//返回删除元素
        /********** End *********/
    }

    /**
     * 返回栈中元素个数
     *
     * @return
     */
    public int size() {
        return size;
    }

    /**
     * 判断一个栈是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        return (null == head);
    }

    //链表结点内部类
    private static class Node<E> {
        private E item;
        private Node<E> next;
    }
}

以下是测试样例: 测试输入:to be or not to - be - - that - - - is 预期输出:to be not that or be

第3关:基于数组的队列

任务描述

像栈一样,队列也是表。但使用队列时,插入在一端进行而删除则在另一端进行。

如同栈的情形一样,任何的表的实现对于队列来说都是合法的。

本关任务:基于数组实现一个循环队列,并具有基本的添加、删除功能。

相关知识
队列

队列实现的是一种先进先出的策略,队列上的插入操作称为入队(enqueue),删除操作称为出队(dequeue)。队列的先进先出特性类似于收银台前排队等待结账的一排顾客。队列有队头(head)和队尾(tail),当有新元素入队时,它被放到队尾的位置,就像一个新到来的顾客排在队伍末端一样。而出队的元素则总是在队头的那个,就像排在队伍前面等待最久的那个顾客一样。下图是一个队列的抽象模型:

头歌java 数据结构之栈、队列 第1关:实现基于数组的栈,java头歌平台,java,数据结构,开发语言

队列的数组实现

对于一个队列数据结构,我们使用一个数组Q,以及队头head和队尾tail的位置来表示。headtail代表队列的两端。下图表明利用数组Q[0...n]来实现一个最多容纳n+1个元素的队列的一种方式。该队列有一个属性Q.head指向队头元素。而属性Q.tail则指向下一个新元素将要插入的位置。队列中的元素存放在位置Q.headQ.head+1……Q.tail-1。初始时有Q.head=Q.tail=0

头歌java 数据结构之栈、队列 第1关:实现基于数组的栈,java头歌平台,java,数据结构,开发语言

入队出队的操作应该是很清楚的。为使一个元素x入队,即执行enqueue(x),让Q[tail]=x,然后使tail1。若使元素出队(dequeue),我们返回Q[head]处的值,且使head1

循环队列

上述这种实现存在一个问题。以上图为例,经过12次入队操作后队列似乎满了,因为此时tail已经超过数组尾端了,再次执行入队操作会造成数组越界。然而,队列中也许只剩下几个元素。因为可能有若干元素出队了。像栈一样,即使有许多操作的情况下,队列也常常不是很大。 一个简单的解决方法是,只要headtail到达数组尾端,它就绕回开头。我们称这种队列称为循环队列。

下图是一个队列实例。

头歌java 数据结构之栈、队列 第1关:实现基于数组的栈,java头歌平台,java,数据结构,开发语言

这里我们利用数组Q[0...12]实现一个循环队列。

  • (a)队列包含5个元素,位于Q[6...10]
  • (b)依次调用Q.enqueue(17)Q.enqueue(3)Q.enqueue(5)后的队列;
  • (c)调用Q.dequeue()方法并返回原队头值15后,队列的构成。此时新的队头是元素6
代码: 
package step3;

/**
 * Created by zengpeng on 2018/1/30.
 */
public class MyQueue<T> {
    private T[] Q;
    private int head;
    private int tail;
    private int size;

    public MyQueue() {
        this(1);
    }

    public MyQueue(int capacity) {
        Q = (T[]) new Object[capacity];
        size = 0;
        head = tail = 0;
    }

    /**
     * 入队操作
     *
     * @param item
     */
    public void enqueue(T item) {
        /********** Begin *********/
        Q[tail]=item;//当前下标添加一个数
        tail=(tail+1)%Q.length;//tail从-1开始,到顶后可能再到头所以要取余
        size++;//元素个数+1
        /********** End *********/
    }

    /**
     * 出队操作
     *
     * @return
     */
    public T dequeue() {

        /********** Begin *********/
        T s=Q[head];//保存要删除元素
        head=(head+1)%Q.length;//同理
        size--;//元素-1
        return s;//返回删除元素
        /********** End *********/
    }

    /**
     * 判断队列是否为空
     * @return
     */
    public boolean isEmpty() {
        return (head == tail) && (size < Q.length);
    }

    public int size() {
        return size;
    }

}

以下是测试样例:

测试输入:to be or not to - be - - that - - - is 预期输出:

  1. to
  2. be
  3. or
  4. not
  5. to
  6. be

第4关:基于链表的队列

任务描述

在上一关,我们用数组实现了队列,但是在使用时需要预先估计所需队列的大小。而链式队列具有内存动态分配,内存利用率高的特点,在一些无法预先估计所需队列大小的场合使用链式队列是一个十分好的选择。

本关任务:实现链式队列,并具备入队、出队操作。

相关知识
链式队列

队列的链式存储结构简称为链式队列。它实际上是一个限制仅在表头删除和表尾插入的单链表。 链式队列的存储结构如下图所示:

头歌java 数据结构之栈、队列 第1关:实现基于数组的栈,java头歌平台,java,数据结构,开发语言

其中`front`指向队头,`tail`指向队尾。出队操作在队头进行,入队操作在队尾进行。 ##### 出队操作

头歌java 数据结构之栈、队列 第1关:实现基于数组的栈,java头歌平台,java,数据结构,开发语言

入队操作

头歌java 数据结构之栈、队列 第1关:实现基于数组的栈,java头歌平台,java,数据结构,开发语言

代码: 
package step4;

import java.util.NoSuchElementException;

/**
 * Created by sykus on 2017/12/29.
 */
public class MyQueue<T> {

    private Node<T> head;// 头结点,不存数据
    private Node<T> front;//指向队头结点
    private Node<T> tail;//指向队尾结点
    private int size;


    public MyQueue() {
        head = new Node<T>();
        front = tail = null;
        size = 0;
    }

    /**
     * 入队
     *
     * @param item
     */
    public void enqueue(T item) {
        /********** Begin *********/
        Node oldTail=tail;//保存旧的队尾
        Node newNode=new Node();//创建新结点
        newNode.item=item;//给新结点添加元素
        if(front==null)//如果为空队列
        {
        head.next=newNode;//头指向新结点
        front=newNode;//队头为新结点
        }
        else//不为
        {
        oldTail.next=newNode;//老队尾指向新结点
        }
        tail=newNode;//令新结点为队尾
        size++;//元素个数+1

        /********** End *********/

    }

    /**
     * 出队
     *
     * @return
     */
    public T dequeue() {
        if (isEmpty())
            throw new NoSuchElementException("队列为空!");

        /********** Begin *********/
        T s=front.item;//保存当前元素
        head.next=front.next;//头指向改为队头的下一个
        front=head.next;//队头改为头的下一个(此时已经为队头的下一个)
        size--;//元素-1
        return s;//返回删除元素

        /********** End *********/

    }

    /**
     * 返回队列中元素数量
     *
     * @return
     */
    public int size() {
        return size;
    }

    /**
     * 判断一个队列是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        return (front == null);
    }

    /**
     * 链表结点内部类
     */
    private static class Node<E> {
        private E item;
        private Node<E> next;
    }
}

 以下是测试样例:

测试输入:to - be or not to - be - - that - - is 预期输出:文章来源地址https://www.toymoban.com/news/detail-857071.html

  1. to be or not to be
  2. 2

到了这里,关于Java 数据结构之栈、队列(头歌平台,详细注释)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

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

    栈和队列是一种特殊的线性结构,他与之前学的线性结构不同,栈和队列是拥有一种特殊规则的线性结构,虽然它是用数组或者链表实现,但是只有符合这种规则才能被称作栈或者队列 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和

    2024年01月16日
    浏览(34)
  • 数据结构之栈和队列---c++

    栈 栈是一个“先进后出”结构 队列 入队演示 队列是一种“先进先出”的结构 出队演示 接下来我们开始本次的内容 分析 1.我们可以 老老实实的写一个栈 然后将所有的接口函数实现出来,最后再进行实现队列,但是显然是 效率低下 的方法 2.我们使用 数组模拟栈 ,然后再进

    2024年02月14日
    浏览(49)
  • 数据结构奇妙旅程之栈和队列

    ꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转载还请通知˶⍤⃝˶ 个人主页:xiaoxieʕ̯

    2024年02月04日
    浏览(33)
  • 数据结构学习分享之栈和队列详解

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:数据结构学习分享⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你了解更多数据结构的知识   🔝🔝 这一节要分享的是一个全新的结构–栈和队列,栈和队列总是会一起出现,因为它们的存储方式刚好相反,一个先进先出一

    2024年02月03日
    浏览(38)
  • Java数据结构之排序(头歌平台,详细注释)

    目录 第1关:选择排序 任务描述 相关知识 代码:    第2关:插入排序 任务描述 相关知识 插入排序 代码:   第3关:归并排序 任务描述 相关知识 归并排序 原理 代码:    第4关:快速排序 任务描述 相关知识 快速排序 代码:    第5关:堆排序 任务描述 相关知识 堆

    2024年01月19日
    浏览(31)
  • 数据结构之栈与队列的实现与详细解析

    个人主页:点我进入主页 专栏分类:C语言初阶      C语言程序设计————KTV       C语言小游戏     C语言进阶 C语言刷题       数据结构初阶 欢迎大家点赞,评论,收藏。 一起努力,一起奔赴大厂。 目录 1.前言 2.栈 2.1栈的概念与性质 2.2栈的实现 3.队列 3.1队列的概

    2024年02月05日
    浏览(35)
  • C语言数据结构——线性表之栈和队列

    为什么会定义栈和队列这两种数据结构呢? 原因在于: 之所以会定义栈和队列这样的数据结构 是因为他们有两大特性 : 第一: 他们可以保存程序运行路径中各个点的信息,以便用于回溯操作或其他需要访问已经访问过的节点信息的操作。 比如: 栈用于解决迷宫问题,就

    2023年04月11日
    浏览(93)
  • 高效学习数据结构之栈和队列篇(五千字超详细教程)

    大家好呀我是小生🙉🙊🙈今天我们来学习 数据结构的栈和队列 ,小生为了方便大家理解特意附上了 许多图片和源码 一起加油吧 🥳🥳🥳   下面是我们今天要学习的内容 🥳🥳🥳  一.栈          1.🏠栈的基本概念 ​2.🏠栈的结构选择 🚀顺序表和链表的优缺点对比:

    2023年04月08日
    浏览(56)
  • 数据结构之栈和队列 - 超详细的教程,手把手教你认识并运用栈和队列

    栈:后进先出 队列:先进先出 栈:是一种特殊的 线性表 , 只允许在固定的一端插入或者删除元素 ,一个栈包含了栈顶和栈底。只能在栈顶插入或者删除元素。 栈的底层 是由 数组 实现的。 栈遵循先入后出原则,也就是先插入的元素得到后面才能删除,后面插入的元素比

    2024年02月07日
    浏览(43)
  • 【头歌】数据结构-队列的应用

      第1关:循环队列 任务描述 本关任务:编写一个循环队列,实现入队、出队操作,判断队空、队满等特殊情况。 相关知识 为了完成本关任务,你需要掌握:1.循环队列定义,2.入队、出队的定义,3.队空、队满的情况。 循环队列定义 循环队列将数组存储区看成是一个首尾相

    2024年02月08日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包