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性能优化之数据结构实例代码的相关内容,包括数据结构的优化方法以及示例代码等。我们使用以下两个示例来说明性能优化的过程和方法。 示例1:字符串拼接 在Java中字符串拼接通常使用”+=”方式,但是在循环中频繁地使用该操作会导致性能问题。这时可以使用StringBuilder类的append()方法…

    数据结构 2023年5月17日
    00
  • Java数据结构之LinkedList的用法详解

    Java数据结构之LinkedList的用法详解 LinkedList简介 LinkedList是Java中的一个数据结构,它是一个双向链表,可以提供快速的插入和删除操作。LinkedList中的元素分别保存在每个节点中,每个节点包含了指向前一个节点和后一个节点的引用。 使用LinkedList的好处是,其可以快速的进行插入和删除操作,但是如果需要随机存取中…

    数据结构 2023年5月17日
    00
  • Redis数据结构之链表详解

    Redis数据结构之链表详解 Redis中,链表是一个非常重要的底层数据结构,被用于实现众多高级数据结构(例如列表、队列等)的底层实现,同时也可以被用户直接使用。这篇文章将详细讲解Redis的链表实现、过程和应用。 链表结构 Redis的链表由多个节点组成,每个节点包含以下三个部分: 前置节点地址(prev) 后置节点地址(next) 节点的值(value)…

    数据结构 2023年5月17日
    00
  • 使用C语言详解霍夫曼树数据结构

    使用C语言详解霍夫曼树数据结构 什么是霍夫曼树 霍夫曼树是一种带权路径长度最短的树,也称为最优二叉树,它是优化编码的核心算法。 在霍夫曼树中,每个叶子节点对应一个字符,该节点的权值为该字符出现的次数。当然,字符可以是任何数据类型。生成霍夫曼树后,在对每个字符进行编码时,字符在霍夫曼树中的路径即为其编码。(一般规定,一条从根到叶子的路径上只出现0或1,从根到某…

    数据结构 2023年5月17日
    00
  • C语言数据结构之 折半查找实例详解

    C语言数据结构之 折半查找实例详解 什么是折半查找? 折半查找是一种在有序数组中查找某个特定元素的算法。其基本思想是将查找的值与数组的中间元素比较,如果比中间元素小,则在数组的左半部分查找;如果比中间元素大,则在数组的右半部分查找,直到找到该元素或查找范围为空。 折半查找算法的流程 确定要查找的数组arr和其元素个数n,以及要查找的元素value。 设定左边…

    数据结构 2023年5月17日
    00
  • Java数据结构之堆(优先队列)详解

    Java数据结构之堆(优先队列)详解 概述 堆是一种基于树的数据结构,它可以用来解决很多问题,例如排序、优先队列等。在堆中,每个节点的值都小于或等于它的子节点的值。堆分为两种类型:最大堆和最小堆。在最大堆中,根节点的值最大;而在最小堆中,根节点的值最小。 堆的操作主要有以下两种: 插入:将一个元素插入到堆中,需要维护堆的性质,即节点的值小于或等于子节点的值。…

    数据结构 2023年5月17日
    00
  • C语言 结构体数组详解及示例代码

    C语言 结构体数组详解及示例代码 结构体是C语言中最为基础的数据结构之一,它可以将多个数据类型组合成一个整体,方便地进行访问和管理。而结构体数组则是将多个相同结构体类型的变量按照一定规律排列在一起的一种数据结构。本文将详细讲解C语言中结构体数组的使用方法及示例代码。 定义结构体 首先,我们需要定义一个结构体类型。结构体类型需要指定名称、成员变量及其数据类型:…

    数据结构 2023年5月17日
    00
  • 详解Java数据结构之平衡二叉树

    详解Java数据结构之平衡二叉树 什么是平衡二叉树? 平衡二叉树(Balanced Binary Tree)是一种特殊的二叉搜索树,它的左子树和右子树的高度差不超过1,这样可以保证在最坏情况下,查找、插入、删除等操作的时间复杂度都是O(log n)。 平衡二叉树的基本性质 左子树和右子树的高度差不超过1。 平衡二叉树的左右子树也是平衡二叉树。 如何实现? 平…

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