数据结构与算法第三天 原创

Piwriw.
发布于 2022-1-20 13:21
浏览
0收藏

春节不停更,此文正在参加「星光计划-春节更帖活动」

前言

  • 这是我在51CTO春节不停更,此文正在参加「星光计划-春节更帖活动」第四天的第四篇文章了,昨天我跟大家分享了一下最简单和最常见的选择排序和插入排序算法,今天我们要开启一个新的内容—:star2:数据结构之栈Stack和队列Queue:star2:,废话不多说,让我们一下看看栈和队列究竟是什么吧?
  • 由于我本身能力限制,我分享的内容更偏向于新手向,但是我希望大家有耐心看完的话,一定会有自己的感悟
  • 由于本人能力有限,在过程中难免会出现错误,以及可能也有存在更好的代码,希望大家在评论区发现错误也能留言,大家一起来讨论这个问题:two_hearts:

什么叫做栈

栈在百度百科中的定义:

  • 栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素()
  • 关于栈的特性:
    • FILO ( 先进后出,first in last out )
  • 关于栈的一些基本操作:
      1. 入栈Push: 其实就是把一个数据添加到栈中
      1. 出栈Pop: 其实就是拿出一个栈里面的数据(由于FILO的特点,其实是拿出了一个栈顶的元素
      1. 获取栈顶元素peek:这里跟出栈Pop不同,我们只是查看栈顶的元素,不改变栈中数据
  • 为了更好的管理一个Stack我们可能还会有如下的操作
      1. getSize():这样可能更好的让我们了解到一个栈Stack的数据量
      1. isEmpty():判断Stack是不是为空栈,其实也可以理解为getSize()中一种比较特殊的情况

如何解读栈Stack

  • 理想图:数据结构与算法第三天-鸿蒙开发者社区
  • 关于栈,我们其实完全可以想象成一个容器,并且这个容器更像一个水杯,我们的数据是一个方块,不是水,下面我用一个搭建房子来说明
    • 每次数据Push入栈的时候,里面的方块就像建房子一样,新增了一层房子。
    • 数据Pop出栈的时候,我们就好像是把最上面那一层的拆掉了,其实我们出栈的时候,我们一般都说是弹出,这个其实很形象
    • 数据peek获取栈顶元素的时候,就是我们看一下我们搭建的房子最上面一层是怎么样的,但是我们不需要拆它的层楼
    • 而当我们执行getSize()的时候,就是看看现在我们有几层房子了
    • isEmpty()的时候,自然是不是看一下有没有建房子,有没有楼层

栈的实现

$\color{ff0000}{下面的代码并非使用的Java代码,作为伪代码,我希望大家能尝试去实现一下我没有给出的部分}$

/**
 * @Author Piwriw.
 * @Date 2022/1/20
 * @motto 你不能做我的诗,正如我不能做你的梦.
 */
 
 /**
 * 数组实现Stack
 */
public class ArrayStack<E> implements Stack<E> {
    Array<E> array;

    public ArrayStack(int capacity) {
        array = new Array<E>(capacity);
    }

    public ArrayStack() {
        array = new Array<E>();
    }

    @Override
    public int getSize() {
        return array.getSize();
    }

    @Override
    public boolean isEmpty() {
        return array.isEmpty();
    }

    @Override
    public void push(E e) {
        array.addLast(e);
    }

    @Override
    public E pop() {
        return array.removeLast();
    }

    @Override
    public E peek() {
        return array.getLast();
    }
}

什么是队列Queue

百度百科对队列的定义:

  • 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头
  • 关于队列Queue的重要特性:
    • LILO( 先进先出 first in first out)
  • 关于队列Queue的一些基础操作
    • dequeue()入队:给队列中添加一个元素
    • enqueue()出队:从队列中移除一个元素
  • 关于队列我们还可能有如下操作
    • getFront():查看队首元素
    • getSize():查看队列的长度
    • isEmpty():判断队列是不是为空

如何解读队列

  • 理想图:数据结构与算法第三天-鸿蒙开发者社区
  • 其实队列从名字上来说远比栈更加贴近,它就是像一个队伍一样,下面我们用小朋友排队伍来说明,我们用一个小朋友代表每一个元素
    • dequeue()操作的时候,我们就是把一个小朋友排到进队中来,并且我们把这个小朋友队伍排到队伍的最后面,我们这个队伍是有方向
    • enqueue()操作的时候,就是让队伍最前面的小朋友离开
    • getFront()操作的时候,就是看看队伍最前面那个小朋友是谁啊,但是我们还没有让他离开
    • getSize()操作的时候,自然而生就是看一下现在我们队伍有多长了
    • isEmpty()操作的时候,就是看看看我们现在这个队伍有小朋友吗?

队列的实现

$\color{ff0000}{下面的代码并非使用的Java代码,作为伪代码,我希望大家能尝试去实现一下我没有给出的部分}$

/**
 * @Author Piwriw.
 * @Date 2022/1/20
 * @motto 你不能做我的诗,正如我不能做你的梦.
 */

/**
 * 数组队列
 * @param <E>
 */
public class ArrayQueue <E> implements Queue<E> {
    private Array<E> array;
    public ArrayQueue(int capacity){
        array=new Array<E>(capacity);
    }
    public ArrayQueue(){
        array=new Array<E>();
    }
    @Override
    public int getSize() {
        return array.getSize();
    }

    @Override
    public boolean isEmpty() {
        return array.isEmpty();
    }

    @Override
    public void enqueue(E e) {
         array.addLast(e);
    }

    @Override
    public E dequeue() {
        return array.removeFirst();
    }

    @Override
    public E getFront() {
        return array.getFirst();
    }
}

下面对于队列的一些补充

其实队列远比我们的栈存在更多的可玩性,比如说循环队列、双向队列等等,下面我想分享一下循环队列

  • 关于循环队列,其实首先循环,一些接触过算法的小伙伴,应该知道一个著名的问题—约瑟夫问题,具体故事大家可以自己进入连接查看,简单来说它通过了一个取余的操作实现了循环,一会我们在实现循环队列的时候也会使用到这个技术
  • 其实循环队列,就是我们引入了头尾指针(指针在Java实际上是没有的,只是我们在这里引入C语言中指针这个概念),$\color{0000ff}{通过了头尾指针取余我们事先规定的队列的长度}$ ,实现了循环队列
代码实现
public class LoopQueue<E> implements Queue<E> {
    private E[] data;
    private int front, tail;
    private int size;

    public LoopQueue(int capacity) {
        data = (E[]) new Object[capacity + 1];
        front = 0;
        tail = 0;
        size = 0;
    }

    public LoopQueue() {
        this(10);
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return front == tail;
    }

    @Override
    public void enqueue(E e) {
        data[tail] = e;
        tail = (tail + 1) % data.length;
        size++;
    }

    @Override
    public E dequeue() {
        if (isEmpty()) {
            throw new IllegalArgumentException("Cannot dequeue from an empty queue.");
        }
        E ret = data[front];
        data[front] = null;
        front = (front + 1) % data.length;
        size--;

        return ret;
    }

    @Override
    public E getFront() {
        if (isEmpty()){
            throw new IllegalArgumentException("Queue is empty");
        }
        return data[front];
    }
}

总结

  • 今天我们学习了数据结构中的栈和队列,这俩种及其重要的数据结构,偷偷告诉你,后面中我们还会用到他们,比如说我们的从DFS(深度优先遍历)到BFS(广度优先遍历),就是加入了栈这种数据结构。不知道,大家学到这里,尤其是对于队列的掌握是不是已经:dizzy_face::dizzy_face::dizzy_face:了,但是我相信大家仔细想想我给出的二个实际的例子,你就会发现其实不管是栈还是队列,这俩种数据结构,都是非常非常形象的,好了我们,我们明天再见吧,预告一下,其实今天的代码存在的很多的缺陷,比如说,我们在实现队列的时候,我写固定好了栈的长度,能不能尝试改造一下它,实现队列的长度是可以改变的呢?:laughing::laughing::laughing:
  • 这次栈的习题,不得不给出一道在力扣上非常好的关于栈的使用:20. 有效的括号,大家要尝试用Stack哦:smirk:
  • 关于构造循环队列,力扣上也是有相关的题目—622. 设计循环队列,快去尝试一下吧
  • 这里是:春节不停更,此文正在参加「星光计划-春节更帖活动」,本人正在计划在这次活动中,跟大家分享一下,我学习数据结构与算法的心得,这是数据结构第三天的栈Stack和队列Queue:laughing::laughing::laughing:

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐