鏈表

一、定義

1.1 概念

在計(jì)算機(jī)科學(xué)中,鏈表是數(shù)據(jù)元素的線性集合,其每個(gè)元素都指向下一個(gè)元素,元素存儲(chǔ)上并不連續(xù)

1.2 分類

  • 單向鏈表:每個(gè)元素只知道其下一個(gè)元素是誰(shuí)
  • 雙向鏈表:每個(gè)元素知道其上一個(gè)元素和下一個(gè)元素
  • 循環(huán)鏈表:通常的鏈表尾節(jié)點(diǎn) tail 指向的都是 null,而循環(huán)鏈表的 tail 指向的是頭節(jié)點(diǎn) head
image.png

鏈表內(nèi)還有一種特殊的節(jié)點(diǎn)稱為哨兵(Sentinel)節(jié)點(diǎn),也叫做啞元( Dummy)節(jié)點(diǎn),它不存儲(chǔ)數(shù)據(jù),通常用作頭尾,用來(lái)簡(jiǎn)化邊界判斷。

隨機(jī)訪問(wèn)性能
根據(jù) index 查找,時(shí)間復(fù)雜度 O(n)

插入或刪除性能

  • 起始位置:O(1)
  • 結(jié)束位置:如果已知 tail 尾節(jié)點(diǎn)是 O(1),不知道 tail 尾節(jié)點(diǎn)是 O(n)
  • 中間位置:根據(jù) index 查找時(shí)間 + O(1)

二、單向鏈表

2.1 定義

public class SinglyLinkedList {

    // 頭節(jié)點(diǎn)
    private SingleNode head; 
    
     // 節(jié)點(diǎn)類
    static class SingleNode {
        private int value;
        private SingleNode next;
        public SingleNode(int value, SingleNode next) {
            this.value = value;
            this.next = next;
        }
    }
}
  • SingleNode 定義為內(nèi)部類,是為了對(duì)外隱藏實(shí)現(xiàn)細(xì)節(jié),沒(méi)必要讓類的使用者關(guān)心 Node 結(jié)構(gòu)
  • 定義為 static 內(nèi)部類,是因?yàn)?SingleNode 不需要與 SinglyLinkedList 實(shí)例相關(guān),多個(gè) SinglyLinkedList實(shí)例能共用 SingleNode 類定義

2.2 頭部添加

    private static void addFirst(int value) {
        //鏈表為空
        // head = new SingleNode(value, null);
        //鏈表非空
        head = new SingleNode(value, head);
    }

2.3 遍歷

public class SinglyLinkedList implements Iterable<Integer> {
    // .....
   /**
     * 遍歷while
     */
    private static void loopWhile(Consumer<Integer> consumer) {
        SingleNode pointer = head;
        while (pointer != null) {
            consumer.accept(pointer.value);
            pointer = pointer.next;
        }
    }

    /**
     * 遍歷for
     *
     * @param consumer
     */
    private static void loopFor(Consumer<Integer> consumer) {
        for (SingleNode pointer = head; pointer != null; pointer = pointer.next) {
            consumer.accept(pointer.value);
        }
    }

    /**
     * 遞歸遍歷
     */
    private static void loopRecursion(Consumer<Integer> before, Consumer<Integer> after) {
        recursion(head, before, after);
    }

    private static void loop(SingleNode node) {
        if (node == null) {
            return;
        }
        System.out.println("before:" + node.value);
        loop(node.next);
        System.out.println("after:" + node.value);
    }

    /**
     * 遞歸調(diào)用
     * @param node
     * @param before
     * @param after
     */
    private static void recursion(SingleNode node, Consumer<Integer> before, Consumer<Integer> after) {
        if (node == null) {
            return;
        }
        before.accept(node.value);
        recursion(node.next, before, after);
        after.accept(node.value);
    }

    // 迭代器遍歷
    private static class IntegerIterator implements Iterator<Integer> {
        // 指針
        SingleNode pointer = head;

        /**
         * 是否有下一個(gè)元素
         *
         * @return
         */
        @Override
        public boolean hasNext() {
            return pointer != null;
        }

        /**
         * 返回當(dāng)前元素,并指向下一個(gè)元素
         *
         * @return
         */
        @Override
        public Integer next() {
            int value = pointer.value;
            pointer = pointer.next;
            return value;
        }
    }

以上遍歷都可以把要做的事以 Consumer 函數(shù)的方式傳遞進(jìn)來(lái)

  • Consumer 的規(guī)則是一個(gè)參數(shù)無(wú)返回值,因此像 System.out::println 方法等都是 Consumer
  • 調(diào)用 Consumer 時(shí),將當(dāng)前節(jié)點(diǎn) curr.value 作為參數(shù)傳遞給它

迭代器遍歷:

  • hasNext 用來(lái)判斷是否還有必要調(diào)用 next
  • next 做兩件事
    • 返回當(dāng)前節(jié)點(diǎn)的 value
    • 指向下一個(gè)節(jié)點(diǎn)

2.4 尾部添加

    /**
     * 尾插
     *
     * @param value
     */
    private static void addLast(int value) {
        SingleNode last = findLast();
        if (last == null) {
            addFirst(value);
        } else {
            last.next = new SingleNode(value, null);
        }
    }

    /**
     * 找到最后一個(gè)元素
     *
     * @return
     */
    private static SingleNode findLast() {
        if (head == null) {
            return null;
        }
        SingleNode pointer = head;
        while (pointer.next != null) {
            pointer = pointer.next;
        }
        return pointer;
    }

2.5 根據(jù)索引獲取元素

    /**
     * 根據(jù)索引獲取節(jié)點(diǎn)值
     *
     * @param index
     * @return
     */
    public static int getNodeVal(int index) {
        SingleNode node = findNode(index);
        if (node == null) {
            throw new IllegalArgumentException(String.format("index [%d] 不合法 %n", index));
        }
        return node.value;
    }

    /**
     * 根據(jù)索引查找節(jié)點(diǎn)
     *
     * @param index
     * @return
     */
    private static SingleNode findNode(int index) {
        int i = 0;
        for (SingleNode pointer = head; pointer != null; pointer = pointer.next, i++) {
            if (i == index) {
                return pointer;
            }
        }
        return null;
    }

2.6 插入元素(任意位置)

    /**
     * 往對(duì)應(yīng)位置index插入元素
     *
     * @param index
     * @param val
     */
    private static void addByIndex(int index, int val) {
        if (index == 0) {
            addFirst(val);
        } else {
            //獲取當(dāng)前要插入的索引的上一個(gè)元素
            SingleNode pre = findNode(index - 1);
            if (pre == null) {
                throw new IllegalArgumentException(String.format("index [%d] 不合法 %n", index));
            }
            pre.next = new SingleNode(val, pre.next);
        }
    }

2.7 刪除元素

    /**
     * 刪除第一個(gè)節(jié)點(diǎn)
     */
    public static void removeFirst() {
        if (head == null) {
            throw new IllegalArgumentException("沒(méi)有可刪除的節(jié)點(diǎn)");
        }
        head = head.next;
    }

    /**
     * 按照索引刪除對(duì)應(yīng)的節(jié)點(diǎn)
     * @param index
     */
    public static void remove(int index) {
        if (index == 0) {
            removeFirst();
        } else {
            SingleNode pre = findNode(index - 1);
            if (pre == null || pre.next == null) {
                throw new IllegalArgumentException("沒(méi)有可刪除的節(jié)點(diǎn)");
            }
            pre.next = pre.next.next;
        }
    }

2.8 帶哨兵的單向鏈表操作

public class SentinelSingleLinkedList implements Iterable<Integer> {

    /**
     * 讓頭指針指向哨兵節(jié)點(diǎn) 減少非空判斷
     */
    private static SingleNode head = new SingleNode(-1,null);

    @Override
    public Iterator<Integer> iterator() {
        return new IntegerIterator();
    }

    static class SingleNode {

        private int value;

        private SingleNode next;

        public SingleNode(int value, SingleNode next) {
            this.value = value;
            this.next = next;
        }
    }

    /**
     * 頭插
     *
     * @param value
     */
    private static void addFirst(int value) {
        //鏈表為空
        // head = new SingleNode(value, null);
        //鏈表非空
        // head = new SingleNode(value, head);
        addByIndex(0, value);
    }


    /**
     * 尾插
     *
     * @param value
     */
    private static void addLast(int value) {
        SingleNode last = findLast();
//        if (last == null) {
//            addFirst(value);
//        } else {
        last.next = new SingleNode(value, null);
//        }
    }

    /**
     * 根據(jù)索引查找節(jié)點(diǎn)
     *
     * @param index
     * @return
     */
    private static SingleNode findNode(int index) {
        int i = -1;
        for (SingleNode pointer = head; pointer != null; pointer = pointer.next, i++) {
            if (i == index) {
                return pointer;
            }
        }
        return null;
    }

    /**
     * 往對(duì)應(yīng)位置index插入元素
     *
     * @param index
     * @param val
     */
    private static void addByIndex(int index, int val) {
//        if (index == 0) {
//            addFirst(val);
//        } else {
        //獲取當(dāng)前要插入的索引的上一個(gè)元素
        SingleNode pre = findNode(index - 1);
        if (pre == null) {
            throw new IllegalArgumentException(String.format("index [%d] 不合法 %n", index));
        }
        pre.next = new SingleNode(val, pre.next);
//        }
    }

    /**
     * 根據(jù)索引獲取節(jié)點(diǎn)值
     *
     * @param index
     * @return
     */
    public static int getNodeVal(int index) {
        SingleNode node = findNode(index);
        if (node == null) {
            throw new IllegalArgumentException(String.format("index [%d] 不合法 %n", index));
        }
        return node.value;
    }

    /**
     * 刪除第一個(gè)節(jié)點(diǎn)
     */
    public static void removeFirst() {
//        if (head == null) {
//            throw new IllegalArgumentException("沒(méi)有可刪除的節(jié)點(diǎn)");
//        }
//        head = head.next;
        remove(0);
    }

    /**
     * 按照索引刪除對(duì)應(yīng)的節(jié)點(diǎn)
     * @param index
     */
    public static void remove(int index) {
//        if (index == 0) {
//            removeFirst();
//        } else {
            SingleNode pre = findNode(index - 1);
            if (pre == null || pre.next == null) {
                throw new IllegalArgumentException("沒(méi)有可刪除的節(jié)點(diǎn)");
            }
            pre.next = pre.next.next;
//        }
    }

    /**
     * 遍歷while
     */
    private static void loopWhile(Consumer<Integer> consumer) {
        SingleNode pointer = head.next;
        while (pointer != null) {
            consumer.accept(pointer.value);
            pointer = pointer.next;
        }
    }

    /**
     * 遍歷for
     *
     * @param consumer
     */
    private static void loopFor(Consumer<Integer> consumer) {
        for (SingleNode pointer = head.next; pointer != null; pointer = pointer.next) {
            consumer.accept(pointer.value);
        }
    }

    /**
     * 找到最后一個(gè)元素
     *
     * @return
     */
    private static SingleNode findLast() {
        // 因?yàn)轭^指針指向的是哨兵 所以不會(huì)為空
//        if (head == null) {
//            return null;
//        }
        SingleNode pointer = head;
        while (pointer.next != null) {
            pointer = pointer.next;
        }
        return pointer;
    }
}

三、雙向鏈表

帶哨兵的雙向鏈表

public class SentinelDoubleLinkedList implements Iterable<Integer> {

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            DoubleNode pointer = head.next;

            @Override
            public boolean hasNext() {
                return pointer != tail;
            }

            @Override
            public Integer next() {
                Integer value = pointer.value;
                pointer = pointer.next;
                return value;
            }
        };
    }

    static class DoubleNode {
        DoubleNode pre;
        int value;
        DoubleNode next;

        public DoubleNode(DoubleNode pre, int value, DoubleNode next) {
            this.pre = pre;
            this.value = value;
            this.next = next;
        }
    }

    /**
     * 頭哨兵
     */
    private static DoubleNode head;

    /**
     * 尾哨兵
     */
    private static DoubleNode tail;

    public SentinelDoubleLinkedList() {
        head = new DoubleNode(null, -1, null);
        tail = new DoubleNode(null, -2, null);
        head.next = tail;
        tail.pre = head;
    }

    /**
     * 根據(jù)索引查找節(jié)點(diǎn)
     *
     * @param index
     * @return
     */
    private static DoubleNode findNodeByIndex(int index) {
        int i = -1;
        for (DoubleNode pointer = head; pointer != tail; i++, pointer = pointer.next) {
            if (i == index) {
                return pointer;
            }
        }
        return null;
    }

    /**
     * 根據(jù)索引位置插入值
     *
     * @param index
     * @param value
     */
    private static void addByIndex(int index, int value) {
        //找到要插入的上一個(gè)節(jié)點(diǎn)
        DoubleNode pre = findNodeByIndex(index - 1);
        if (pre == null) {
            throw new IllegalArgumentException();
        }
        DoubleNode next = pre.next;
        //要插入的新節(jié)點(diǎn)
        DoubleNode node = new DoubleNode(pre, value, next);
        pre.next = node;
        next.pre = node;
    }

    /**
     * 從頭部添加節(jié)點(diǎn)
     *
     * @param value
     */
    private static void addFirst(int value) {
        addByIndex(0, value);
    }

    /**
     * 從尾部添加節(jié)點(diǎn)
     *
     * @param value
     */
    private static void addLast(int value) {
        // 最后一個(gè)節(jié)點(diǎn)
        DoubleNode last = tail.pre;
        DoubleNode node = new DoubleNode(last, value, tail);
        last.next = node;
        tail.pre = node;
    }

    /**
     * 刪除第一個(gè)節(jié)點(diǎn)
     */
    public void removeFirst() {
        removeByIndex(0);
    }

    /**
     * 刪除最后一個(gè)節(jié)點(diǎn)
     */
    public void removeLast() {
        if (tail.pre == head) {
            throw new IllegalArgumentException();
        }
        // 最后一個(gè)節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)
        DoubleNode node = tail.pre.pre;
        node.next = tail;
        tail.pre = node;
    }

    /**
     * 按索引刪除節(jié)點(diǎn)
     *
     * @param index
     */
    public void removeByIndex(int index) {
        // 要?jiǎng)h除的上一個(gè)
        DoubleNode pre = findNodeByIndex(index - 1);
        // 找不到pre或者要?jiǎng)h除的是尾哨兵的時(shí)候
        if (pre == null || pre.next == tail) {
            throw new IllegalArgumentException();
        }
        // 要?jiǎng)h除的下一個(gè)
        DoubleNode next = pre.next.next;

        pre.next = next;
        next.pre = pre;
    }
}

四、雙向環(huán)形鏈表

哨兵既作為頭,也作為尾

image.png

帶哨兵的雙向環(huán)形鏈表

public class SentinelDoubleCircularLinkedList implements Iterable<Integer> {

    // 哨兵節(jié)點(diǎn)
    private static DoubleCircularNode sentinel = new DoubleCircularNode(null, -1, null);

    public SentinelDoubleCircularLinkedList() {
        sentinel.pre = sentinel;
        sentinel.next = sentinel;
    }

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {

            DoubleCircularNode pointer = sentinel.next;

            @Override
            public boolean hasNext() {
                return pointer != sentinel;
            }

            @Override
            public Integer next() {
                Integer value = pointer.value;
                pointer = pointer.next;
                return value;
            }
        };
    }

    private static class DoubleCircularNode {
        DoubleCircularNode pre;
        int value;
        DoubleCircularNode next;

        public DoubleCircularNode(DoubleCircularNode pre, int value, DoubleCircularNode next) {
            this.pre = pre;
            this.value = value;
            this.next = next;
        }
    }

    /**
     * 從頭部添加節(jié)點(diǎn)
     */
    private static void addFirst(int value) {
        //前驅(qū)
        DoubleCircularNode pre = sentinel;
        // 后繼
        DoubleCircularNode next = sentinel.next;
        DoubleCircularNode node = new DoubleCircularNode(pre, value, next);

        pre.next = node;
        next.pre = node;
    }

    /**
     * 從尾部添加節(jié)點(diǎn)
     *
     * @param value
     */
    private static void addLast(int value) {
        DoubleCircularNode node = new DoubleCircularNode(sentinel.pre, value, sentinel);
        sentinel.pre.next = node;
        sentinel.pre = node;
    }

    /**
     * 從頭部刪除節(jié)點(diǎn)
     */
    private static void removeFirst() {
        //要?jiǎng)h除的元素
        DoubleCircularNode remove = sentinel.next;
        if (remove == sentinel) {
            throw new IllegalArgumentException();
        }
        sentinel.next = remove.next;
        remove.next.pre = sentinel;
    }

    /**
     * 從尾部刪除節(jié)點(diǎn)
     */
    private static void removeLast() {
        //要?jiǎng)h除的節(jié)點(diǎn)
        DoubleCircularNode remove = sentinel.pre;
        if (remove == sentinel) {
            throw new IllegalArgumentException();
        }
        remove.pre.next = sentinel;
        sentinel.pre = remove.pre;
    }

    /**
     * 根據(jù)值刪除對(duì)應(yīng)的節(jié)點(diǎn)
     */
    private static void removeByValue(int value) {
        //要?jiǎng)h除的節(jié)點(diǎn)
        DoubleCircularNode remove = findByValue(value);
        if (remove == null) {
            return;
        }
        remove.pre.next = remove.next;
        remove.next.pre = remove.pre;
    }

    /**
     * 根據(jù)值查找節(jié)點(diǎn)
     *
     * @return
     */
    private static DoubleCircularNode findByValue(int value) {
        DoubleCircularNode pointer = sentinel.next;
        while (pointer != sentinel) {
            if (pointer.value == value) {
                return pointer;
            }
            pointer = pointer.next;
        }
        return null;
    }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評(píng)論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 178,980評(píng)論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 64,064評(píng)論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,779評(píng)論 6 414
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 56,109評(píng)論 1 330
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 43,287評(píng)論 0 291
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評(píng)論 1 338
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,515評(píng)論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,750評(píng)論 1 375
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,933評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 35,327評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 36,667評(píng)論 1 296
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,492評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,703評(píng)論 2 380

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

  • 2.2 鏈表 概述 定義 在計(jì)算機(jī)科學(xué)中,鏈表是數(shù)據(jù)元素的線性集合,其每個(gè)元素都指向下一個(gè)元素,元素存儲(chǔ)上并不連續(xù)...
    康小莊閱讀 1,032評(píng)論 0 1
  • 鏈表(Linked list)是一種常見(jiàn)的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),是一種線性表,但是并不會(huì)按線性的順序存儲(chǔ)數(shù)據(jù),而是在每一個(gè)...
    人月神話Lee閱讀 188評(píng)論 0 0
  • 線性表 定義:線性表就是數(shù)據(jù)排成像一條線一樣的結(jié)構(gòu)。每個(gè)線性表上的數(shù)據(jù)最多只有前和后兩個(gè)方向。其實(shí)除了數(shù)組,鏈表、...
    竹blue閱讀 333評(píng)論 0 0
  • 一、什么是鏈表? 和數(shù)組一樣,鏈表也是一種線性表。 從內(nèi)存結(jié)構(gòu)來(lái)看,鏈表的內(nèi)存結(jié)構(gòu)是不連續(xù)的內(nèi)存空間,是將一組零散...
    蹩腳的小三閱讀 1,062評(píng)論 0 0
  • 前言 Redis鏈表為雙向無(wú)環(huán)鏈表! Redis使用了簡(jiǎn)單動(dòng)態(tài)字符串,鏈表、字典(散列表)、跳躍表、整數(shù)集合、壓縮...
    小波同學(xué)閱讀 533評(píng)論 0 4