動手實現(xiàn)基于數(shù)組的棧和隊列

基礎(chǔ)知識

棧(stack)又名堆棧晒奕,它是一種運算受限的線性表匾效。其限制是僅允許在表的一端進行插入和刪除運算。

棧是一種后進先出(LIFO)的數(shù)據(jù)結(jié)構(gòu)翠储。

隊列

隊列是一種特殊的線性表爆哑,特殊之處在于它只允許在表的前端(front)進行刪除操作洞难,而在表的后端(rear)進行插入操作,和棧一樣揭朝,隊列是一種操作受限制的線性表队贱。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭萝勤。

隊列是一種先進先出(FIFO)的數(shù)據(jù)結(jié)構(gòu)露筒。

制定手寫方案

如果我們要手寫一個椖派。或者隊列敌卓,先要確定用什么數(shù)據(jù)結(jié)構(gòu)保存數(shù)據(jù),需要實現(xiàn)哪些功能伶氢?

選取數(shù)據(jù)結(jié)構(gòu)

為了更好的理解棧和隊列的原理趟径,盡量采用簡單的數(shù)據(jù)結(jié)構(gòu)來保存數(shù)據(jù),這樣實現(xiàn)的邏輯會變得簡單易懂癣防,所以本次采用的是數(shù)組蜗巧。

實現(xiàn)哪些功能

對于棧:

  • 入棧和出棧
  • 獲取棧頂元素但不刪除此元素
  • 獲取棧是否為空的方法
  • 獲取棧大小的方法

對于隊列:

  • 進隊列和出隊列
  • 獲取隊列頭元素但不刪除此元素
  • 獲取隊列是否為空的方法
  • 獲取隊列大小的方法

使用數(shù)組實現(xiàn)棧:

import java.util.Arrays;
import java.util.EmptyStackException;


class Stack<E> {
    private E[] _data; // 數(shù)據(jù)
    private int _size; // 數(shù)組長度
    private int _realLength; // 數(shù)組已用長度

    @SuppressWarnings("unchecked")
    public Stack(int initSize) {
        this._size = initSize;
        this._data = (E[]) new Object[initSize];
        this._realLength = 0;
    }

    /**
     * 默認數(shù)組長度為20
     */
    public Stack() {
        this(20);
    }

    /**
     * 入棧
     *
     * @param element 添加的元素
     */
    public void push(E element) {
        if (size() >= _size) {
            grow();
        }
        _data[_realLength++] = element;
    }

    /**
     * 出棧
     *
     * @return 返回棧頂?shù)脑?     */
    public E pop() {
        if (size() < 1) {
            throw new EmptyStackException();
        }
        E top = _data[_realLength - 1];
        _data[--_realLength] = null;
        return top;
    }

    /**
     * 獲取棧頂元素
     *
     * @return 返回的是棧頂元素
     */
    public E peek() {
        if (size() < 1) {
            throw new EmptyStackException();
        }
        return _data[_realLength - 1];
    }

    /**
     * 判斷棧是否為空棧
     *
     * @return true代表空棧
     */
    public boolean isEmpty() {
        return _realLength == 0;
    }

    /**
     * 棧的大小
     *
     * @return 大小值
     */
    public int size() {
        return _realLength;
    }

    /**
     * 數(shù)組的擴容,擴容大小為原先的2倍
     */
    private void grow() {
        // 擴容后size也要變化
        _size = _size * 2;
        _data = Arrays.copyOf(_data, _size);
    }

    public static void main(String[] args) {
        Stack<Integer> stack = new Stack<>(1);
        stack.push(0);
        stack.push(1);
        stack.push(2);
        stack.push(3);
        System.out.println("stack is empty: " + stack.isEmpty());
        System.out.println("stack size is: " + stack.size());
        System.out.println("stack pop is: " + stack.pop());
        System.out.println("stack top is: " + stack.peek());
        // stack is empty: false
        // stack size is: 4
        // stack pop is: 3
        // stack top is: 2
    }
}

需要注意的幾個點:

  • 數(shù)組的擴容蕾盯,做法是每次擴容原先長度的2倍
  • 出棧后數(shù)組的變更幕屹,元素出棧后需要將之前的元素置空,便于 GC
  • 對數(shù)組越界問題的把握,只要涉及到獲取元素的操作望拖,都需要對下標(biāo)進行是否越界判斷渺尘,可以返回 null,也可以直接拋出異常说敏,具體看個人

使用數(shù)組實現(xiàn)隊列:

import java.util.Arrays;
import java.util.NoSuchElementException;


/**
 * FIFO
 */
class Queue<E> {

    private E[] _data;
    private int _realLength;
    private int _size;

    @SuppressWarnings("unchecked")
    public Queue(int initSize) {
        this._data = (E[]) new Object[initSize];
        this._size = initSize;
        this._realLength = 0;
    }

    /**
     * 默認數(shù)組長度為20
     */
    public Queue() {
        this(20);
    }

    /**
     * 向隊列尾端添加元素
     *
     * @param element 元素
     */
    public void offer(E element) {
        if (size() >= _size) {
            grow();
        }
        _data[_realLength++] = element;
    }

    /**
     * 取出隊列頭元素鸥跟,并且從隊列中刪除它
     *
     * @return 頭元素
     */
    public E poll() {
        if (isEmpty()) {
            throw new NoSuchElementException("queue is empty");
        }
        E first = _data[0];
        _data = Arrays.copyOfRange(_data, 1, _size);
        _realLength--;
        return first;
    }

    /**
     * 取出隊列頭元素,但是不刪除它
     *
     * @return 頭元素
     */
    public E element() {
        if (isEmpty()) {
            throw new NoSuchElementException("queue is empty");
        }
        return _data[0];
    }

    /**
     * 判斷隊列是否為空
     *
     * @return true代表空隊列
     */
    public boolean isEmpty() {
        return _realLength == 0;
    }

    /**
     * 隊列的大小
     *
     * @return 大小值
     */
    public int size() {
        return _realLength;
    }

    /**
     * 數(shù)組的擴容盔沫,擴容大小為原先的2倍
     */
    private void grow() {
        // 擴容后size也要變化
        _size = _size * 2;
        _data = Arrays.copyOf(_data, _size);
    }

    public static void main(String[] args) {
        Queue<Integer> queue = new Queue<Integer>();
        queue.offer(0);
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        System.out.println("queue is empty: " + queue.isEmpty());
        System.out.println("queue size is: " + queue.size());
        System.out.println("queue poll: " + queue.poll());
        System.out.println("queue poll: " + queue.poll());
        System.out.println("queue poll: " + queue.poll());
        System.out.println("queue poll: " + queue.poll());
        // queue is empty: false
        // queue size is: 4
        // queue poll: 0
        // queue poll: 1
        // queue poll: 2
        // queue poll: 3
    }
}

使用數(shù)組來實現(xiàn)隊列相比較棧更加的容易医咨,添加元素、判空和 size() 兩者都相似架诞,只是在出隊列的時候做法與出棧不相同而已拟淮,出隊列出的是頭部元素,也就是最先添加的元素侈贷,出隊列之后需要重新調(diào)整數(shù)組惩歉,使用系統(tǒng)提供的 Arrays.copyOfRange(_data, 1, _size) 可輕松的復(fù)制數(shù)組一段元素。

手寫棧和隊列不僅可以用數(shù)組來實現(xiàn)俏蛮,也可以用鏈表來實現(xiàn)撑蚌,用鏈表可以可以更好的控制添加和刪除操作,畢竟鏈表采用的是指針方案搏屑。有興趣的可以自行實現(xiàn)一波争涌。

如果本文章你發(fā)現(xiàn)有不正確或者不足之處,歡迎你在下方留言或者掃描下方的二維碼留言也可辣恋!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末亮垫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子伟骨,更是在濱河造成了極大的恐慌饮潦,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件携狭,死亡現(xiàn)場離奇詭異继蜡,居然都是意外死亡,警方通過查閱死者的電腦和手機逛腿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進店門稀并,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人单默,你說我怎么就攤上這事碘举。” “怎么了搁廓?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵引颈,是天一觀的道長耕皮。 經(jīng)常有香客問我,道長蝙场,這世上最難降的妖魔是什么明场? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮李丰,結(jié)果婚禮上苦锨,老公的妹妹穿的比我還像新娘。我一直安慰自己趴泌,他們只是感情好舟舒,可當(dāng)我...
    茶點故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著嗜憔,像睡著了一般秃励。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吉捶,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天夺鲜,我揣著相機與錄音,去河邊找鬼呐舔。 笑死币励,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的珊拼。 我是一名探鬼主播食呻,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼澎现!你這毒婦竟也來了仅胞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤剑辫,失蹤者是張志新(化名)和其女友劉穎干旧,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妹蔽,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡椎眯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了讹开。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盅视。...
    茶點故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡捐名,死狀恐怖旦万,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情镶蹋,我是刑警寧澤成艘,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布赏半,位于F島的核電站,受9級特大地震影響淆两,放射性物質(zhì)發(fā)生泄漏断箫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一秋冰、第九天 我趴在偏房一處隱蔽的房頂上張望仲义。 院中可真熱鬧,春花似錦剑勾、人聲如沸埃撵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽暂刘。三九已至,卻和暖如春捂刺,著一層夾襖步出監(jiān)牢的瞬間谣拣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工族展, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留森缠,地道東北人。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓仪缸,卻偏偏與公主長得像辅鲸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子腹殿,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,554評論 2 349

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