图解数据结构:栈和队列

前言

阅读此篇之前,强烈建议先仔细阅读上一篇 图解数据结构:数组和单链表 ,会有事半功倍的效果,并且此篇的代码,基本上是复用上一篇的实现。

上一篇主要讲解了数组和链表这两种线性结构的特点、区别、时间复杂度分析等。对数组和链表的划分,实际上是物理结构(存储结构)的划分。
物理结构有两种基本的结构:顺序存储结构、链式存储结构。而本篇所讲解的栈和队列属于逻辑结构上的划分。逻辑结构分为线性结构、非线性结构。

  • 线性结构:有且仅有一个开始节点和一个终端节点,每个节点最多只有一个直接前驱和一个直接后继。代表结构:栈、队列
  • 非线性结构:一个节点可能有多个直接前驱和多个直接后继。代表结构:树、图

本篇主要讲解栈和队列的特点、区别,以及用数组和链表分别实现栈和队列。

堆栈(英语:stack)又称为栈或堆叠,是计算机科学中的一种抽象数据类型,只允许在有序的线性数据集合的一端(称为堆栈顶端,英语:top)进行加入数据(英语:push)和移除数据(英语:pop)的运算。因而按照后进先出(LIFO, Last In First Out)的原理运作。

栈的主要特点就是LIFO(Last In First Out,后进先出),并且程序只能操作栈的一端,被操作的一端叫做栈顶(Top)。所以栈的使用非常简单,但是实现的功能却非常强大。
栈的主要操作有两个个:入栈(push)、出栈(pop)。

入栈(push)

入栈操作
如图所示,栈就像一个瓶子,只有一个口。三个元素A、B、C先后入栈,先入栈的放在底部,后入栈的放在上面。

出栈(pop)

出栈操作
根据图示,栈顶的元素最先出栈。这与入栈的顺序刚好相反,入栈顺序是A->B->C,出栈顺序是C->B->A。也就是说:栈是LIFO(Last In First Out,后进先出的)。
看似简单的栈,应用十分广泛。操作系统的函数调用、各类编辑器的撤销操作的实现都离不开栈。

栈有两种实现方式:顺序栈链式栈

顺序栈

顺序栈用数组实现,基于上一篇 图解数据结构:数组和单链表 ,我们实现了动态数组,实际上用数组实现栈,就是将数组的增、删操作限制在头部或者尾部,即只能在数组的一端操作元素,就成了顺序栈,复用上一篇的代码,实现顺序栈就很简单了。

// 动态数组实现顺序栈
public class ArrayStack<E> {

	// 此处ArrayList为上一篇博客所实现的
    private ArrayList<E> list;

    public ArrayStack() {
        list = new ArrayList();
    }

    /**
     * 入栈
     * @param e
     * @return
     */
    public E push(E e) {
        list.add(e);
        return e;
    }

    /**
     * 出栈
     * @return
     */
    public E pop() {
        return list.remove();
    }

    /**
     * 查看栈顶元素
     * @return
     */
    public E peek() {
        return list.get(list.size() - 1);
    }
}

注意:pop()peek()方法都能返回栈顶元素,pop()方法会删除栈顶元素,也就是出栈。而peek()方法仅仅是查看栈顶元素,不会删除栈顶元素。
以上几个方法的时间复杂度在动态数组ArrayList中都已经分析过了,此处不再赘述。
完整代码下载地址:
Github:ArrayStack.java

链式栈

链式栈是用链表实现栈,也就是上一篇实现的LinkedList。由于复用了上一篇的代码,所以实现起来也非常简单,基本上只需要把顺序栈中ArrayList换成LinkedList就可以了。

队列

队列,又称为伫列(queue),是先进先出(FIFO, First-In-First-Out)的线性表。在具体应用中通常用链表或者数组来实现。队列只允许在后端(称为rear)进行插入操作,在前端(称为front)进行删除操作。
队列的操作方式和堆栈类似,唯一的区别在于队列只允许新数据在后端进行添加。

与栈(stack)不同的是,队列是FIFO(First In First Out,先进先出),进入队列的一端叫尾部(rear),出队列的一端叫头部(front)。队列的主要操作也有两个:入队(offer)、出队(poll)

入队

入队操作
从图中可以看到,A、B、C三个元素都是从队尾(rear)进入,就像现实生活中的排队,先来的就排在前面。

出队

出队操作
从图中可以看出,出队的顺序是A->B->C,也就是入队的顺序,即说明了队列是遵循FIFO的。队列的引用也十分广泛,锁的实现、生产者-消费者模型等都离不开队列。

队列也有两种实现方式:顺序队列链式队列

顺序队列

顺序队列用数组实现,基于上一篇 图解数据结构:数组和单链表 ,我们实现了动态数组,用数组实现队列,就是将数组的增操作限制在尾部,删操作限制在头部,即分别只能在数组的一端操作元素,就成了顺序队列,复用上一篇的代码。

public class ArrayQueue<E> {

	// 此处ArrayList为上一篇博客所实现的
    private ArrayList<E> list;

    public ArrayQueue() {
        list = new ArrayList();
    }

    /**
     * 出队
     * @param e
     */
    public void offer(E e) {
        list.add(e);
    }

    /**
     * 入队
     * @return
     */
    public E poll() {
        return list.remove(0);
    }

    /**
     * 查看队列头部元素
     * @return
     */
    public E peek() {
        return list.get(0);
    }

}

注意:poll()peek()方法都能返回队列头部元素,poll()方法会删除队列头部元素,也就是出队。而peek()方法仅仅是查看队列头部元素,不会删除队列头部元素。
完整代码下载地址:
Github:ArrayQueue.java

链式队列

链式队列是用链表实现队列,也就是上一篇实现的LinkedList。由于复用了上一篇的代码,所以实现起来也非常简单,基本上只需要把顺序队列中ArrayList换成LinkedList就可以了。

总结

对于栈和队列的简单实现,其实上一篇就已经实现过了,所以本篇的重点是理解栈和队列的工作方式、结构区别、使用区别等。栈和队列是比较简单的线性结构,但是简单不代表用得少。实际上栈和队列的应用非常广泛,理解其工作原理,是使用好栈和队列的第一步,也是最重要的一步。

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
数据结构是计算机科学中非常重要的概念之一,它用于组织和存储数据以便有效地操作和访问。Java语言提供了丰富的数据结构库,包括数组、链表、队列、树、图等。我将为你图解一些常见的数据结构及其在Java中的实现。 1. 数组(Array):数组是一种线性数据结构,它按照顺序存储相同类型的元素。在Java中,数组的大小在创建时就确定,并且可以通过索引访问和修改其中的元素。 2. 链表(Linked List):链表是一种动态数据结构,它由节点组成,每个节点包含数据和指向下一个节点的引用。在Java中,有单向链表和双向链表两种常见的实现方式。 3. Stack):是一种后进先出(LIFO)的数据结构,类似于我们生活中的一叠盘子。在Java中,可以使用Stack类或者使用LinkedList类来实现。 4. 队列Queue):队列是一种先进先出(FIFO)的数据结构,类似于我们日常生活中排队等待的情况。在Java中,可以使用Queue接口或者使用LinkedList类来实现队列。 5. 树(Tree):树是一种非线性的数据结构,它由节点和边组成,每个节点可以有多个子节点。在Java中,常见的树结构包括二叉树、二叉搜索树(BST)、AVL树、红黑树等。 6. 图(Graph):图是一种由节点和边组成的数据结构,节点表示实体,边表示实体之间的关系。在Java中,可以使用邻接矩阵或邻接表来表示图,并通过深度优先搜索(DFS)或广度优先搜索(BFS)等算法来遍历图。 这些只是数据结构中的一部分,Java还提供了其他更复杂的数据结构和算法库,可以根据具体需求选择合适的数据结构。希望以上图解能够帮助你更好地理解数据结构在Java中的实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值