【Java实现】栈和队列就是这么简单

一、前言

上一篇已经讲过了链表【Java实现单向链表】了,它跟数组都是线性结构的基础,本文主要讲解线性结构的应用:队列

如果写错的地方希望大家能够多多体谅并指正哦,如果有更好的理解的方式也希望能够在评论下留言,让大家学习学习~

二、数据结构【栈】就是这么简单

2.1数据结构【栈】介绍

数据结构的栈长的是这个样子:

image

其实非常好理解,我们将栈可以看成一个箱子

  • 往箱子里面放东西叫做入栈
  • 往箱子里面取东西叫做出栈
  • 箱子的底部叫做栈底
  • 箱子的顶部叫做栈顶

说到栈的特性,肯定会有一句经典的言语来概括:先进后出(LIFO, Last In First Out)

  • 往箱子里边放苹果,箱子底部的苹果想要拿出来,得先把箱子顶部的苹果取走才行

2.2数据结构【栈】 代码实现

栈的分类有两种:

  • 静态栈(数组实现)
  • 动态栈(链表实现)

从上一篇写链表我就认知到我的算法是有多渣了,普通的单链表操作也能把我绕得晕晕的。

由于我的链表还不是很熟,栈又不是很难,那么我就用链表来创建动态栈了!

既然是用链表,我们还是把上一篇节点的代码拿过来吧:


public class Node {

    //数据域
    public int data;

    //指针域,指向下一个节点
    public Node next;

    public Node() {
    }

    public Node(int data) {
        this.data = data;
    }

    public Node(int data, Node next) {
        this.data = data;
        this.next = next;
    }

}

要链表用来表示栈,这次会有两个指针:

  • 栈顶
  • 栈底

public class Stack {

    public Node stackTop;
    public Node stackBottom;

    public Stack(Node stackTop, Node stackBottom) {
        this.stackTop = stackTop;
        this.stackBottom = stackBottom;
    }

    public Stack() {
    }

}

2.2.1进栈

将原本栈顶指向的节点交由新节点来指向,栈顶指向新加入的节点


    /**
     * 进栈
     *
     * @param stack 栈
     * @param value 要进栈的元素
     */
    public static void pushStack(Stack stack, int value) {

        // 封装数据成节点
        Node newNode = new Node(value);

        // 栈顶本来指向的节点交由新节点来指向
        newNode.next = stack.stackTop;

        // 栈顶指针指向新节点
        stack.stackTop = newNode;

    }

2.2.2遍历栈

只要栈顶元素的指针不指向栈底,那么就一直输出遍历结果:


    /**
     * 遍历栈(只要栈顶指针不指向栈底指针,就一直输出)
     *
     * @param stack
     */
    public static void traverse(Stack stack) {
        Node stackTop = stack.stackTop;

        while (stackTop != stack.stackBottom) {

            System.out.println("关注公众号:Java3y:" + stackTop.data);

            stackTop = stackTop.next;
        }

    }

测试:


    public static void main(String[] args) {

        //初始化栈(无元素)
        Stack stack = new Stack(new Node(), new Node());

        //栈顶和栈尾是同一指向
        stack.stackBottom = stack.stackTop;

        //指向null
        stack.stackTop.next = null;

        //进栈
        pushStack(stack, 3);
        pushStack(stack, 4);
        pushStack(stack, 5);

        traverse(stack);

    }

结果:

image

这就符合了先进后出的特性了~

2.2.3判断该栈是否为空

很简单,只要栈顶和栈底是同一指向,那么该栈就为空


    /**
     * 判断该栈是否为空
     *
     * @param stack
     */
    public static void isEmpty(Stack stack) {
        if (stack.stackTop == stack.stackBottom) {

            System.out.println("关注公众号:Java3y---->该栈为空");
        } else {

            System.out.println("关注公众号:Java3y---->该栈不为空");

        }

    }

2.2.4出栈

  1. 在出栈之前看看该栈是否为空,不为空才出栈...
  2. 将栈顶的元素的指针(指向下一个节点)赋值给栈顶指针(完成出栈)
    /**
     * 出栈(将栈顶的指针指向下一个节点)
     * @param stack
     */
    public static void popStack(Stack stack) {

        // 栈不为空才能出栈
        if (!isEmpty(stack)) {

            //栈顶元素
            Node top = stack.stackTop;

            // 栈顶指针指向下一个节点
            stack.stackTop = top.next;

            System.out.println("关注公众号:Java3y---->出栈的元素是:" + top.data);

        }
    }

测试出栈:

image

多次出栈:

image

2.2.5清空栈

当时学C的时候需要释放内存资源,可是Java不用呀,所以栈顶指向栈底,就清空栈了


    /**
     * 清空栈
     * @param stack
     */
    public static void clearStack(Stack stack) {

        stack.stackTop = null;
        stack.stackBottom = stack.stackTop;
    }

三、数据结构【队列】就是这么简单

数据结构的队列长的是这个样子:

image

其实队列非常好理解,我们将队列可以看成小朋友排队

  • 队尾的小朋友到指定的地点了-->出队
  • 有新的小朋友加入了-->入队

相对于栈而言,队列的特性是:先进先出

  • 先排队的小朋友肯定能先打到饭!

队列也分成两种:

  • 静态队列(数组实现)
  • 动态队列(链表实现)

这次我就使用数组来实现静态队列了。值得注意的是:往往实现静态队列,我们都是做成循环队列

image

做成循环队列的好处是不浪费内存资源

3.1数据结构【队列】 代码实现

这次我们使用的是数组来实现静态队列,因此我们可以这样设计:


public class Queue {

    //数组
    public int [] arrays;

    //指向第一个有效的元素
    public int front;

    //指向有效数据的下一个元素(即指向无效的数据)
    public int rear;

}

从上面的设计我们可以发现:rear并不指向最后一个有效的元素,在循环队列中这样设计是非常方便的!因为这样设计可以让我们分得清队头和队尾(不然循环队列不断入队或出队,位置是变化很快的)

由于我们是循环队列,所以frontrear值会经常变动,我们得把frontrear的值限定在一个范围内,不然会超出队列的长度的。

有这么一个算法:rear=(rear+1)%数组长度

  • 比如rear的下标是2,数组的长度是6,往后面移一位是3,那么rear = (rear+1) % 6,结果还是3

3.1.2初始化队列

此时队列为空,分配了6个长度给数组(只能装5个实际的数字,rear指向的是无效的位置的)


    public static void main(String[] args) {

        //初始化队列
        Queue queue = new Queue();

        queue.front = 0;
        queue.rear = 0;
        queue.arrays = new int[6];

    }

3.1.3判断队列是否满了

如果rear指针和front指针紧挨着,那么说明队列就满了


    /**
     * 判断队列是否满了,front和rear指针紧挨着,就是满了
     * @param queue
     * @return
     */
    public static boolean isFull(Queue queue) {
        if ((queue.rear + 1) % queue.arrays.length == queue.front) {

            System.out.println("关注公众号:Java3y--->此时队列满了!");
            return true;
        } else {
            System.out.println("关注公众号:Java3y--->此时队列没满了!");
            return false;
        }
    }

3.1.4入队

  1. 判断该队列是否满了
  2. 入队的值插入到队尾中(具体的位置就是rear指针的位置【再次声明:rear指向的是无效元素的位置】
  3. rear指针移动(再次指向无效的元素位置)

    /**
     * 入队
     *
     * @param queue
     */
    public static void enQueue(Queue queue,int value) {

        // 不是满的队列才能入队
        if (!isFull(queue)) {

            // 将新的元素插入到队尾中
            queue.arrays[queue.rear] = value;

            // rear节点移动到新的无效元素位置上
            queue.rear = (queue.rear + 1) % queue.arrays.length;
        }
    }

3.1.5遍历

只要front节点不指向rear节点,那么就可以一直输出


    /**
     * 遍历队列
     * @param queue
     *
     */
    public static void traverseQueue(Queue queue) {

        // front的位置
        int i = queue.front;

        while (i != queue.rear) {

            System.out.println("关注公众号:Java3y--->" + queue.arrays[i]);

            //移动front
            i = (i + 1) % queue.arrays.length;
        }

    }

队列没满时:

image

队列已满了就插入不了了(验证上面的方法是否正确):

image

3.1.6判断该队列是否为空

只要rearfront指针指向同一个位置,那该队列就是空的了


    /**
     * 判断队列是否空,front和rear指针相等,就是空了
     * @param queue
     * @return
     */
    public static boolean isEmpty(Queue queue) {
        if (queue.rear  == queue.front) {
            System.out.println("关注公众号:Java3y--->此时队列空的!");
            return true;
        } else {
            System.out.println("关注公众号:Java3y--->此时队列非空!");
            return false;
        }
    }

3.1.7出队

出队的逻辑也非常简单:

  1. 判断该队列是否为null
  2. 如果不为null,则出队,只要front指针往后面移就是出队了!

    /**
     * 出队
     *
     * @param queue
     */
    public static void outQueue(Queue queue) {

        //判断该队列是否为null
        if (!isEmpty(queue)) {

            //不为空才出队
            int value = queue.arrays[queue.front];
            System.out.println("关注公众号:Java3y--->出队的元素是:" + value);

            // front指针往后面移
            queue.front = (queue.front + 1) % queue.arrays.length;

        }

    }

结果:

image

四、总结

数据结构的栈和队列的应用非常非常的多,这里也只是最简单的入门,理解起来也不困难。

  • 栈:先进后出
  • 队列:先进先出

关于数据结构这方面我就到暂时到这里为止了,都简单的入个门,以后遇到更加复杂的再继续开新的文章来写~毕竟现在水平不够,也无法理解更深层次的东西~数据结构这东西是必备的,等到研究集合的时候还会来回顾它,或者遇到新的、复杂的也会继续学习....

想要更加深入数据结构的同学就得去翻阅相关的书籍咯~这仅仅是冰山一角

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容