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

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

1. 栈的概念

栈(Stack)是一种先进后出的数据结构,类似于一个箱子,新的物品只能放到箱子的顶部,旧的物品只能从箱子的顶部取出。栈通常有下面几个基本操作:

  1. push:将元素压入栈中,放在栈顶。
  2. pop:将栈顶元素弹出,如果栈为空,则抛出异常。
  3. peek:返回栈顶元素,但不将其弹出,如果栈为空,则抛出异常。
  4. isEmpty:判断栈是否为空。
  5. size:返回栈的元素数量。

2. 栈的实现

数组实现

数组实现栈非常简单,使用一个数组和一个指针top来实现,top表示栈顶元素的位置。具体实现代码如下:

public class ArrayStack<E> {

    private static final int DEFAULT_CAPACITY = 10;

    private Object[] data; // 栈数组
    private int top; // 栈顶指针
    private int size; // 栈内元素数量

    // 构造函数,可以指定初始容量
    public ArrayStack(int initialCapacity) {
        if (initialCapacity <= 0) {
            throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
        }
        data = new Object[initialCapacity];
        top = -1;
    }

    // 默认构造函数,容量为10
    public ArrayStack() {
        this(DEFAULT_CAPACITY);
    }

    public void push(E item) {
        if (size == data.length) {
            resize(data.length * 2);
        }
        data[++top] = item;
        size++;
    }

    public E pop() {
        if (isEmpty()) {
            throw new NoSuchElementException("Stack is empty");
        }
        E item = (E) data[top];
        data[top--] = null; // help gc
        size--;
        if (size > 0 && size == data.length / 4) {
            resize(data.length / 2);
        }
        return item;
    }

    public E peek() {
        if (isEmpty()) {
            throw new NoSuchElementException("Stack is empty");
        }
        return (E) data[top];
    }

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

    public int size() {
        return size;
    }

    private void resize(int capacity) {
        Object[] newData = new Object[capacity];
        for (int i = 0; i < size; i++) {
            newData[i] = data[i];
        }
        data = newData;
    }
}

链表实现

链表实现栈同样非常简单,使用一个链表和一个指针top来实现,top表示栈顶元素的位置。

public class LinkedListStack<E> {

    private Node top; // 栈顶指针
    private int size; // 栈内元素数量

    public void push(E item) {
        top = new Node(item, top);
        size++;
    }

    public E pop() {
        if (isEmpty()) {
            throw new NoSuchElementException("Stack is empty");
        }
        E item = top.item;
        top = top.next;
        size--;
        return item;
    }

    public E peek() {
        if (isEmpty()) {
            throw new NoSuchElementException("Stack is empty");
        }
        return top.item;
    }

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

    public int size() {
        return size;
    }

    private class Node {
        E item;
        Node next;

        Node(E item, Node next) {
            this.item = item;
            this.next = next;
        }
    }
}

3. 队列的概念

队列(Queue)是一种先进先出的数据结构,类似于排队。新来的人只能排在队尾,离开的人只能从队首离开。队列通常有下面几个基本操作:

  1. add:将元素插入队尾。
  2. remove:删除并返回队首元素,如果队列为空,则抛出异常。
  3. element:返回队首元素,但不将其移除,如果队列为空,则抛出异常。
  4. offer:将元素插入队尾,与add方法类似,但是如果队列已满,则返回false。
  5. poll:删除并返回队首元素,与remove方法类似,但是如果队列为空,则返回null。
  6. peek:返回队首元素,但不将其移除,与element方法类似,但是如果队列为空,则返回null。

4. 队列的实现

数组实现

数组实现队列同样非常简单,使用一个数组和两个指针front和rear来实现,front表示队首元素的位置,rear表示队尾元素的位置。具体实现代码如下:

public class ArrayQueue<E> {

    private static final int DEFAULT_CAPACITY = 10;

    private Object[] data; // 队列数组
    private int front; // 队首指针
    private int rear; // 队尾指针
    private int size; // 队列元素数量

    public ArrayQueue(int initialCapacity) {
        if (initialCapacity <= 0) {
            throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
        }
        data = new Object[initialCapacity];
        front = 0;
        rear = -1;
    }

    public ArrayQueue() {
        this(DEFAULT_CAPACITY);
    }

    public void add(E item) {
        if (size == data.length) {
            resize(data.length * 2);
        }
        data[++rear % data.length] = item;
        size++;
    }

    public E remove() {
        if (isEmpty()) {
            throw new NoSuchElementException("Queue is empty");
        }
        E item = (E) data[front];
        data[front++] = null; // help gc
        size--;
        if (size > 0 && size == data.length / 4) {
            resize(data.length / 2);
        }
        return item;
    }

    public E element() {
        if (isEmpty()) {
            throw new NoSuchElementException("Queue is empty");
        }
        return (E) data[front];
    }

    public boolean offer(E item) {
        if (size == data.length) {
            return false;
        }
        data[++rear % data.length] = item;
        size++;
        return true;
    }

    public E poll() {
        if (isEmpty()) {
            return null;
        }
        return remove();
    }

    public E peek() {
        if (isEmpty()) {
            return null;
        }
        return (E) data[front];
    }

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

    public int size() {
        return size;
    }

    private void resize(int capacity) {
        Object[] newData = new Object[capacity];
        for (int i = 0, j = front; i < size; i++, j++) {
            newData[i] = data[j % data.length];
        }
        data = newData;
        front = 0;
        rear = size - 1;
    }
}

链表实现

链表实现队列也非常简单,使用一个链表和两个指针front和rear来实现,front表示队首元素的位置,rear表示队尾元素的位置。

public class LinkedListQueue<E> {

    private Node front; // 队首指针
    private Node rear; // 队尾指针
    private int size; // 队列元素数量

    public void add(E item) {
        Node node = new Node(item, null);
        if (rear == null) {
            front = node;
            rear = node;
        } else {
            rear.next = node;
            rear = node;
        }
        size++;
    }

    public E remove() {
        if (isEmpty()) {
            throw new NoSuchElementException("Queue is empty");
        }
        E item = front.item;
        front = front.next;
        if (front == null) {
            rear = null;
        }
        size--;
        return item;
    }

    public E element() {
        if (isEmpty()) {
            throw new NoSuchElementException("Queue is empty");
        }
        return front.item;
    }

    public boolean offer(E item) {
        Node node = new Node(item, null);
        if (rear == null) {
            front = node;
            rear = node;
        } else {
            rear.next = node;
            rear = node;
        }
        size++;
        return true;
    }

    public E poll() {
        if (isEmpty()) {
            return null;
        }
        return remove();
    }

    public E peek() {
        if (isEmpty()) {
            return null;
        }
        return front.item;
    }

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

    public int size() {
        return size;
    }

    private class Node {
        E item;
        Node next;

        Node(E item, Node next) {
            this.item = item;
            this.next = next;
        }
    }
}

5. 示例说明

示例1: 使用栈实现括号匹配

我们可以使用栈来实现括号匹配,思路如下:

  1. 从左到右扫描字符串中的每个括号。
  2. 如果是左括号,则将其压入栈中。
  3. 如果是右括号,则从栈中弹出一个元素。
  4. 如果弹出的元素不是相应的左括号,则说明括号不匹配,返回false。
  5. 如果扫描完整个字符串后栈为空,则说明括号匹配,返回true。

代码实现如下:

public class BracketMatch {

    public static boolean isMatch(String s) {
        if (s == null || s.isEmpty()) {
            return true;
        }
        ArrayStack<Character> stack = new ArrayStack<>();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == '(' || c == '[' || c == '{') {
                stack.push(c);
            } else if (c == ')' || c == ']' || c == '}') {
                if (stack.isEmpty()) {
                    return false;
                }
                char top = stack.pop();
                if ((c == ')' && top != '(')
                        || (c == ']' && top != '[')
                        || (c == '}' && top != '{')) {
                    return false;
                }
            }
        }
        return stack.isEmpty();
    }
}

示例2: 使用队列实现击鼓传花

我们可以使用队列来实现击鼓传花,思路如下:

  1. 从1号到n号给每个人标上编号,形成一个环状队列。
  2. 从第一个人开始报数(1,则出队列),将花传给下一个人,再重新进入队列。
  3. 不断进行此操作,直到最后只剩下一个人。

代码实现如下:

public class PassGame {

    public static int play(int n, int m) {
        ArrayQueue<Integer> queue = new ArrayQueue<>();
        for (int i = 1; i <= n; i++) {
            queue.add(i);
        }
        while (queue.size() > 1) {
            for (int i = 1; i < m; i++) {
                queue.add(queue.remove());
            }
            queue.remove();
        }
        return queue.remove();
    }
}

6. 总结

本文详细讲解了栈和队列的概念和实现方式,通过两个示例说明了如何使用栈和队列解决实际问题。栈和队列是基本的数据结构之一,本文的内容适合初学者学习。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java深入了解数据结构之栈与队列的详解 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • Java数据结构之简单链表的定义与实现方法示例

    Java数据结构之简单链表的定义与实现方法示例 什么是链表 链表是线性数据结构的一种,它是由一个个节点构成的,每个节点包含两个部分,一个是数据,另一个是指向下一个节点的引用,通俗的说,就像火车一样,每节火车都是一个节点,而每车头都指向下一节车厢。 链表的定义 Java中常用链表有单向链表和双向链表,单向链表每个节点只有一个指向下一个节点的引用,而双向链表每个…

    数据结构 2023年5月17日
    00
  • C语言数据结构之顺序数组的实现

    C语言数据结构之顺序数组的实现 前言 顺序数组是数据结构的一个重要部分,它代表着一种基本的数据结构,能够在数据存储与访问方面发挥极大的作用。本文将详细讲解如何在C语言中实现顺序数组。 简介 顺序数组是在物理内存中顺序存储的一组元素数据,可以通过下标访问任意一个元素。通常情况下,顺序数组的数据类型是相同的,而且每一个元素的大小也是相同的。 实现 实现顺序数组主…

    数据结构 2023年5月17日
    00
  • 稀疏数组

    引入 当在网页上下棋类游戏时,玩到中途想要离开,但是我们需要保存进度,方便下次继续 我们应该怎么实现 ? 以围棋举例 使用二维数组将棋盘记下 ,如 0 为 没有棋子 ,1 为 黑子 , 2为白子 但是没有棋子的地方都为 0 ,整个二维数组充斥着大量的无效数据 0 我们需要想一个办法来 优化存储的方式 基本介绍 当一个数组中大部分元素是同一个值时,我们可以使用…

    算法与数据结构 2023年4月25日
    00
  • python数据结构树和二叉树简介

    下面是关于“Python数据结构树和二叉树简介”的详细攻略。 一、树的概念 树(Tree)是一种非常重要的数据结构,它是由n(n>0)个有限节点组成一个具有层次关系的集合。其中一个节点被称作根节点,它没有父节点;除根节点外,其他节点都有且只有一个父节点;每个节点可以有0个或多个子节点。一棵树的深度为树中层次最大的节点层数,根节点层次为1。 二、二叉树的…

    数据结构 2023年5月17日
    00
  • C语言深入讲解链表的使用

    C语言深入讲解链表的使用 什么是链表? 链表是一种常用的数据结构,它的存储方式是通过指针相互连接实现的。链表是由若干个节点(node)构成的,每个节点都存储着一些信息和指向下一个节点的指针。 链表实现的基本操作 链表的基本操作包括插入节点、删除节点以及遍历链表。我们下面将通过代码示例详细介绍这些操作。 插入节点 链表的插入节点操作是指在链表的某一位置插入一个…

    数据结构 2023年5月17日
    00
  • C语言植物大战数据结构希尔排序算法

    C语言植物大战数据结构希尔排序算法 什么是希尔排序 希尔排序是一种基于插入排序的排序算法,也叫做“缩小增量排序”。和插入排序不同的是,希尔排序的插入排序是对一定间隔的元素进行插入排序,而不是对数组中相邻的元素进行排序。 希尔排序的流程和方法 希尔排序的主要流程是根据元素间的间隔d,分组进行插入排序,依次减小d值。最后当d=1的时候,再按照插入排序的方法对整个…

    数据结构 2023年5月17日
    00
  • Java数据结构之实现哈希表的分离链接法

    Java数据结构之实现哈希表的分离链接法 哈希表是一种非常常用的数据结构,它将数据存储在一个数组中,每个数组元素都存储着链表中的一个节点,这样可以实现高效的数据存储和查找操作。在哈希表中,我们可以通过哈希函数将关键字映射到数组中的特定位置。 但是,当哈希表的负载因子过高时,就会造成哈希冲突,这意味着两个或更多的关键字映射到了同一个数组位置。一种常见的解决方案…

    数据结构 2023年5月17日
    00
  • java数据结构基础:稀疏数组

    Java数据结构基础:稀疏数组 在开发过程中,我们需要处理一些稀疏矩阵(大部分元素为0)的数据。这时候,使用稀疏数组是比较高效的方法。 什么是稀疏数组 稀疏数组是由很多元素值相同的元素组成,这些元素的值通常为0。而这些值不同时都存储在一个数组中会浪费很多内存空间。因此,我们使用稀疏数组来存储这些元素。 稀疏数组的定义: 稀疏数组的行数可以理解为矩阵的行数,而…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部