【Java實(shí)現(xiàn)】棧和隊(duì)列就是這么簡單

一、前言

上一篇已經(jīng)講過了鏈表【Java實(shí)現(xiàn)單向鏈表】了蹬敲,它跟數(shù)組都是線性結(jié)構(gòu)的基礎(chǔ)榄笙,本文主要講解線性結(jié)構(gòu)的應(yīng)用:隊(duì)列

如果寫錯(cuò)的地方希望大家能夠多多體諒并指正哦,如果有更好的理解的方式也希望能夠在評論下留言挖垛,讓大家學(xué)習(xí)學(xué)習(xí)~

二、數(shù)據(jù)結(jié)構(gòu)【棻牛】就是這么簡單

2.1數(shù)據(jù)結(jié)構(gòu)【椓《荆】介紹

數(shù)據(jù)結(jié)構(gòu)的棧長的是這個(gè)樣子:

image

其實(shí)非常好理解,我們將棽仙可以看成一個(gè)箱子

  • 往箱子里面放東西叫做入棧
  • 往箱子里面取東西叫做出棧
  • 箱子的底部叫做棧底
  • 箱子的頂部叫做棧頂

說到棧的特性哪替,肯定會(huì)有一句經(jīng)典的言語來概括:先進(jìn)后出(LIFO, Last In First Out)

  • 往箱子里邊放蘋果,箱子底部的蘋果想要拿出來菇怀,得先把箱子頂部的蘋果取走才行

2.2數(shù)據(jù)結(jié)構(gòu)【椘静埃】 代碼實(shí)現(xiàn)

棧的分類有兩種:

  • 靜態(tài)棧(數(shù)組實(shí)現(xiàn))
  • 動(dòng)態(tài)棧(鏈表實(shí)現(xiàn))

從上一篇寫鏈表我就認(rèn)知到我的算法是有多渣了,普通的單鏈表操作也能把我繞得暈暈的爱沟。

由于我的鏈表還不是很熟库快,棧又不是很難,那么我就用鏈表來創(chuàng)建動(dòng)態(tài)棧了钥顽!

既然是用鏈表义屏,我們還是把上一篇節(jié)點(diǎn)的代碼拿過來吧:


public class Node {

    //數(shù)據(jù)域
    public int data;

    //指針域,指向下一個(gè)節(jié)點(diǎn)
    public Node next;

    public Node() {
    }

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

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

}

要鏈表用來表示棧蜂大,這次會(huì)有兩個(gè)指針:

  • 棧頂
  • 棧底

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進(jìn)棧

將原本棧頂指向的節(jié)點(diǎn)交由新節(jié)點(diǎn)來指向闽铐,棧頂指向新加入的節(jié)點(diǎn)


    /**
     * 進(jìn)棧
     *
     * @param stack 棧
     * @param value 要進(jìn)棧的元素
     */
    public static void pushStack(Stack stack, int value) {

        // 封裝數(shù)據(jù)成節(jié)點(diǎn)
        Node newNode = new Node(value);

        // 棧頂本來指向的節(jié)點(diǎn)交由新節(jié)點(diǎn)來指向
        newNode.next = stack.stackTop;

        // 棧頂指針指向新節(jié)點(diǎn)
        stack.stackTop = newNode;

    }

2.2.2遍歷棧

只要棧頂元素的指針不指向棧底,那么就一直輸出遍歷結(jié)果:


    /**
     * 遍歷棧(只要棧頂指針不指向棧底指針奶浦,就一直輸出)
     *
     * @param stack
     */
    public static void traverse(Stack stack) {
        Node stackTop = stack.stackTop;

        while (stackTop != stack.stackBottom) {

            System.out.println("關(guān)注公眾號(hào):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;

        //進(jìn)棧
        pushStack(stack, 3);
        pushStack(stack, 4);
        pushStack(stack, 5);

        traverse(stack);

    }

結(jié)果:

image

這就符合了先進(jìn)后出的特性了~

2.2.3判斷該棧是否為空

很簡單兄墅,只要棧頂和棧底是同一指向,那么該棧就為空


    /**
     * 判斷該棧是否為空
     *
     * @param stack
     */
    public static void isEmpty(Stack stack) {
        if (stack.stackTop == stack.stackBottom) {

            System.out.println("關(guān)注公眾號(hào):Java3y---->該棧為空");
        } else {

            System.out.println("關(guān)注公眾號(hào):Java3y---->該棧不為空");

        }

    }

2.2.4出棧

  1. 在出棧之前看看該棧是否為空澳叉,不為空才出棧...
  2. 將棧頂?shù)脑氐闹羔?指向下一個(gè)節(jié)點(diǎn))賦值給棧頂指針(完成出棧)
    /**
     * 出棧(將棧頂?shù)闹羔樦赶蛳乱粋€(gè)節(jié)點(diǎn))
     * @param stack
     */
    public static void popStack(Stack stack) {

        // 棧不為空才能出棧
        if (!isEmpty(stack)) {

            //棧頂元素
            Node top = stack.stackTop;

            // 棧頂指針指向下一個(gè)節(jié)點(diǎn)
            stack.stackTop = top.next;

            System.out.println("關(guān)注公眾號(hào):Java3y---->出棧的元素是:" + top.data);

        }
    }

測試出棧:

image

多次出棧:

image

2.2.5清空棧

當(dāng)時(shí)學(xué)C的時(shí)候需要釋放內(nèi)存資源隙咸,可是Java不用呀,所以棧頂指向棧底成洗,就清空棧了


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

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

三五督、數(shù)據(jù)結(jié)構(gòu)【隊(duì)列】就是這么簡單

數(shù)據(jù)結(jié)構(gòu)的隊(duì)列長的是這個(gè)樣子:

image

其實(shí)隊(duì)列非常好理解,我們將隊(duì)列可以看成小朋友排隊(duì)

  • 隊(duì)尾的小朋友到指定的地點(diǎn)了-->出隊(duì)
  • 有新的小朋友加入了-->入隊(duì)

相對于棧而言瓶殃,隊(duì)列的特性是:先進(jìn)先出

  • 先排隊(duì)的小朋友肯定能先打到飯充包!

隊(duì)列也分成兩種:

  • 靜態(tài)隊(duì)列(數(shù)組實(shí)現(xiàn))
  • 動(dòng)態(tài)隊(duì)列(鏈表實(shí)現(xiàn))

這次我就使用數(shù)組來實(shí)現(xiàn)靜態(tài)隊(duì)列了。值得注意的是:往往實(shí)現(xiàn)靜態(tài)隊(duì)列遥椿,我們都是做成循環(huán)隊(duì)列

image

做成循環(huán)隊(duì)列的好處是不浪費(fèi)內(nèi)存資源基矮!

3.1數(shù)據(jù)結(jié)構(gòu)【隊(duì)列】 代碼實(shí)現(xiàn)

這次我們使用的是數(shù)組來實(shí)現(xiàn)靜態(tài)隊(duì)列淆储,因此我們可以這樣設(shè)計(jì):


public class Queue {

    //數(shù)組
    public int [] arrays;

    //指向第一個(gè)有效的元素
    public int front;

    //指向有效數(shù)據(jù)的下一個(gè)元素(即指向無效的數(shù)據(jù))
    public int rear;

}

從上面的設(shè)計(jì)我們可以發(fā)現(xiàn):rear并不指向最后一個(gè)有效的元素,在循環(huán)隊(duì)列中這樣設(shè)計(jì)是非常方便的家浇!因?yàn)檫@樣設(shè)計(jì)可以讓我們分得清隊(duì)頭和隊(duì)尾(不然循環(huán)隊(duì)列不斷入隊(duì)或出隊(duì)本砰,位置是變化很快的)

由于我們是循環(huán)隊(duì)列,所以frontrear值會(huì)經(jīng)常變動(dòng)钢悲,我們得把frontrear的值限定在一個(gè)范圍內(nèi)点额,不然會(huì)超出隊(duì)列的長度的。

有這么一個(gè)算法:rear=(rear+1)%數(shù)組長度

  • 比如rear的下標(biāo)是2譬巫,數(shù)組的長度是6,往后面移一位是3督笆,那么rear = (rear+1) % 6芦昔,結(jié)果還是3

3.1.2初始化隊(duì)列

此時(shí)隊(duì)列為空,分配了6個(gè)長度給數(shù)組(只能裝5個(gè)實(shí)際的數(shù)字娃肿,rear指向的是無效的位置的)


    public static void main(String[] args) {

        //初始化隊(duì)列
        Queue queue = new Queue();

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

    }

3.1.3判斷隊(duì)列是否滿了

如果rear指針和front指針緊挨著咕缎,那么說明隊(duì)列就滿了


    /**
     * 判斷隊(duì)列是否滿了,front和rear指針緊挨著料扰,就是滿了
     * @param queue
     * @return
     */
    public static boolean isFull(Queue queue) {
        if ((queue.rear + 1) % queue.arrays.length == queue.front) {

            System.out.println("關(guān)注公眾號(hào):Java3y--->此時(shí)隊(duì)列滿了凭豪!");
            return true;
        } else {
            System.out.println("關(guān)注公眾號(hào):Java3y--->此時(shí)隊(duì)列沒滿了!");
            return false;
        }
    }

3.1.4入隊(duì)

  1. 判斷該隊(duì)列是否滿了
  2. 入隊(duì)的值插入到隊(duì)尾中(具體的位置就是rear指針的位置【再次聲明:rear指向的是無效元素的位置】
  3. rear指針移動(dòng)(再次指向無效的元素位置)

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

        // 不是滿的隊(duì)列才能入隊(duì)
        if (!isFull(queue)) {

            // 將新的元素插入到隊(duì)尾中
            queue.arrays[queue.rear] = value;

            // rear節(jié)點(diǎn)移動(dòng)到新的無效元素位置上
            queue.rear = (queue.rear + 1) % queue.arrays.length;
        }
    }

3.1.5遍歷

只要front節(jié)點(diǎn)不指向rear節(jié)點(diǎn)晒杈,那么就可以一直輸出


    /**
     * 遍歷隊(duì)列
     * @param queue
     *
     */
    public static void traverseQueue(Queue queue) {

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

        while (i != queue.rear) {

            System.out.println("關(guān)注公眾號(hào):Java3y--->" + queue.arrays[i]);

            //移動(dòng)front
            i = (i + 1) % queue.arrays.length;
        }

    }

隊(duì)列沒滿時(shí):

image

隊(duì)列已滿了就插入不了了(驗(yàn)證上面的方法是否正確):

image

3.1.6判斷該隊(duì)列是否為空

只要rearfront指針指向同一個(gè)位置嫂伞,那該隊(duì)列就是空的了


    /**
     * 判斷隊(duì)列是否空,front和rear指針相等拯钻,就是空了
     * @param queue
     * @return
     */
    public static boolean isEmpty(Queue queue) {
        if (queue.rear  == queue.front) {
            System.out.println("關(guān)注公眾號(hào):Java3y--->此時(shí)隊(duì)列空的帖努!");
            return true;
        } else {
            System.out.println("關(guān)注公眾號(hào):Java3y--->此時(shí)隊(duì)列非空!");
            return false;
        }
    }

3.1.7出隊(duì)

出隊(duì)的邏輯也非常簡單:

  1. 判斷該隊(duì)列是否為null
  2. 如果不為null粪般,則出隊(duì)拼余,只要front指針往后面移就是出隊(duì)了!

    /**
     * 出隊(duì)
     *
     * @param queue
     */
    public static void outQueue(Queue queue) {

        //判斷該隊(duì)列是否為null
        if (!isEmpty(queue)) {

            //不為空才出隊(duì)
            int value = queue.arrays[queue.front];
            System.out.println("關(guān)注公眾號(hào):Java3y--->出隊(duì)的元素是:" + value);

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

        }

    }

結(jié)果:

image

四、總結(jié)

數(shù)據(jù)結(jié)構(gòu)的棧和隊(duì)列的應(yīng)用非常非常的多亩歹,這里也只是最簡單的入門匙监,理解起來也不困難。

  • 棧:先進(jìn)后出
  • 隊(duì)列:先進(jìn)先出

關(guān)于數(shù)據(jù)結(jié)構(gòu)這方面我就到暫時(shí)到這里為止了小作,都簡單的入個(gè)門亭姥,以后遇到更加復(fù)雜的再繼續(xù)開新的文章來寫~畢竟現(xiàn)在水平不夠,也無法理解更深層次的東西~數(shù)據(jù)結(jié)構(gòu)這東西是必備的顾稀,等到研究集合的時(shí)候還會(huì)來回顧它致份,或者遇到新的、復(fù)雜的也會(huì)繼續(xù)學(xué)習(xí)....

想要更加深入數(shù)據(jù)結(jié)構(gòu)的同學(xué)就得去翻閱相關(guān)的書籍咯~這僅僅是冰山一角

如果文章有錯(cuò)的地方歡迎指正础拨,大家互相交流氮块。習(xí)慣在微信看技術(shù)文章绍载,想要獲取更多的Java資源的同學(xué),可以關(guān)注微信公眾號(hào):Java3y

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末滔蝉,一起剝皮案震驚了整個(gè)濱河市击儡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蝠引,老刑警劉巖阳谍,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異螃概,居然都是意外死亡矫夯,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門吊洼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來训貌,“玉大人,你說我怎么就攤上這事冒窍〉莼Γ” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵综液,是天一觀的道長款慨。 經(jīng)常有香客問我,道長谬莹,這世上最難降的妖魔是什么檩奠? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮附帽,結(jié)果婚禮上笆凌,老公的妹妹穿的比我還像新娘。我一直安慰自己士葫,他們只是感情好乞而,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著慢显,像睡著了一般爪模。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上荚藻,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天屋灌,我揣著相機(jī)與錄音,去河邊找鬼应狱。 笑死共郭,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播除嘹,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼写半,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了尉咕?” 一聲冷哼從身側(cè)響起叠蝇,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎年缎,沒想到半個(gè)月后悔捶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡单芜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年蜕该,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洲鸠。...
    茶點(diǎn)故事閱讀 38,605評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡堂淡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出坛怪,到底是詐尸還是另有隱情淤齐,我是刑警寧澤股囊,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布袜匿,位于F島的核電站,受9級(jí)特大地震影響稚疹,放射性物質(zhì)發(fā)生泄漏居灯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一内狗、第九天 我趴在偏房一處隱蔽的房頂上張望怪嫌。 院中可真熱鬧,春花似錦柳沙、人聲如沸岩灭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽噪径。三九已至,卻和暖如春数初,著一層夾襖步出監(jiān)牢的瞬間找爱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工泡孩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留车摄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像吮播,于是被迫代替她去往敵國和親变屁。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容