Java數(shù)據(jù)結(jié)構(gòu)和算法(七)——鏈表

前面博客我們?cè)谥v解數(shù)組中蛔溃,知道數(shù)組作為數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)有一定的缺陷。在無(wú)序數(shù)組中篱蝇,搜索性能差,在有序數(shù)組中徽曲,插入效率又很低零截,而且這兩種數(shù)組的刪除效率都很低,并且數(shù)組在創(chuàng)建后秃臣,其大小是固定了涧衙,設(shè)置的過(guò)大會(huì)造成內(nèi)存的浪費(fèi),過(guò)小又不能滿足數(shù)據(jù)量的存儲(chǔ)奥此。

本篇博客我們將講解一種新型的數(shù)據(jù)結(jié)構(gòu)——鏈表弧哎。我們知道數(shù)組是一種通用的數(shù)據(jù)結(jié)構(gòu),能用來(lái)實(shí)現(xiàn)棧稚虎、隊(duì)列等很多數(shù)據(jù)結(jié)構(gòu)撤嫩。而鏈表也是一種使用廣泛的通用數(shù)據(jù)結(jié)構(gòu),它也可以用來(lái)作為實(shí)現(xiàn)棧蠢终、隊(duì)列等數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ)序攘,基本上除非需要頻繁的通過(guò)下標(biāo)來(lái)隨機(jī)訪問(wèn)各個(gè)數(shù)據(jù),否則很多使用數(shù)組的地方都可以用鏈表來(lái)代替寻拂。

但是我們需要說(shuō)明的是程奠,鏈表是不能解決數(shù)據(jù)存儲(chǔ)的所有問(wèn)題的,它也有它的優(yōu)點(diǎn)和缺點(diǎn)祭钉。本篇博客我們介紹幾種常見(jiàn)的鏈表瞄沙,分別是單向鏈表、雙端鏈表、有序鏈表距境、雙向鏈表以及有迭代器的鏈表泛粹。并且會(huì)講解一下抽象數(shù)據(jù)類型(ADT)的思想,如何用 ADT 描述棧和隊(duì)列肮疗,如何用鏈表代替數(shù)組來(lái)實(shí)現(xiàn)棧和隊(duì)列晶姊。

1、鏈表(Linked List)

鏈表通常由一連串節(jié)點(diǎn)組成伪货,每個(gè)節(jié)點(diǎn)包含任意的實(shí)例數(shù)據(jù)(data fields)和一或兩個(gè)用來(lái)指向上一個(gè)/或下一個(gè)節(jié)點(diǎn)的位置的鏈接("links")

鏈表(Linked list)是一種常見(jiàn)的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)们衙,是一種線性表,但是并不會(huì)按線性的順序存儲(chǔ)數(shù)據(jù)碱呼,而是在每一個(gè)節(jié)點(diǎn)里存到下一個(gè)節(jié)點(diǎn)的指針(Pointer)蒙挑。

使用鏈表結(jié)構(gòu)可以克服數(shù)組鏈表需要預(yù)先知道數(shù)據(jù)大小的缺點(diǎn),鏈表結(jié)構(gòu)可以充分利用計(jì)算機(jī)內(nèi)存空間愚臀,實(shí)現(xiàn)靈活的內(nèi)存動(dòng)態(tài)管理忆蚀。但是鏈表失去了數(shù)組隨機(jī)讀取的優(yōu)點(diǎn),同時(shí)鏈表由于增加了結(jié)點(diǎn)的指針域姑裂,空間開(kāi)銷比較大馋袜。

2、單向鏈表(Single-Linked List)

單鏈表是鏈表中結(jié)構(gòu)最簡(jiǎn)單的舶斧。一個(gè)單鏈表的節(jié)點(diǎn)(Node)分為兩個(gè)部分欣鳖,第一個(gè)部分(data)保存或者顯示關(guān)于節(jié)點(diǎn)的信息,另一個(gè)部分存儲(chǔ)下一個(gè)節(jié)點(diǎn)的地址茴厉。最后一個(gè)節(jié)點(diǎn)存儲(chǔ)地址的部分指向空值泽台。

單向鏈表只可向一個(gè)方向遍歷,一般查找一個(gè)節(jié)點(diǎn)的時(shí)候需要從第一個(gè)節(jié)點(diǎn)開(kāi)始每次訪問(wèn)下一個(gè)節(jié)點(diǎn)矾缓,一直訪問(wèn)到需要的位置怀酷。而插入一個(gè)節(jié)點(diǎn),對(duì)于單向鏈表嗜闻,我們只提供在鏈表頭插入蜕依,只需要將當(dāng)前插入的節(jié)點(diǎn)設(shè)置為頭節(jié)點(diǎn),next指向原頭節(jié)點(diǎn)即可泞辐。刪除一個(gè)節(jié)點(diǎn)笔横,我們將該節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn)的next指向該節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)。

image

在表頭增加節(jié)點(diǎn):

image

刪除節(jié)點(diǎn):

image

①咐吼、單向鏈表的具體實(shí)現(xiàn)

package com.ys.datastructure;

public class SingleLinkedList {
    private int size;//鏈表節(jié)點(diǎn)的個(gè)數(shù)
    private Node head;//頭節(jié)點(diǎn)
    
    public SingleLinkedList(){
        size = 0;
        head = null;
    }
    
    //鏈表的每個(gè)節(jié)點(diǎn)類
    private class Node{
        private Object data;//每個(gè)節(jié)點(diǎn)的數(shù)據(jù)
        private Node next;//每個(gè)節(jié)點(diǎn)指向下一個(gè)節(jié)點(diǎn)的連接
        
        public Node(Object data){
            this.data = data;
        }
    }
    
    //在鏈表頭添加元素
    public Object addHead(Object obj){
        Node newHead = new Node(obj);
        if(size == 0){
            head = newHead;
        }else{
            newHead.next = head;
            head = newHead;
        }
        size++;
        return obj;
    }
    
    //在鏈表頭刪除元素
    public Object deleteHead(){
        Object obj = head.data;
        head = head.next;
        size--;
        return obj;
    }
    
    //查找指定元素吹缔,找到了返回節(jié)點(diǎn)Node,找不到返回null
    public Node find(Object obj){
        Node current = head;
        int tempSize = size;
        while(tempSize > 0){
            if(obj.equals(current.data)){
                return current;
            }else{
                current = current.next;
            }
            tempSize--;
        }
        return null;
    }
    
    //刪除指定的元素锯茄,刪除成功返回true
    public boolean delete(Object value){
        if(size == 0){
            return false;
        }
        Node current = head;
        Node previous = head;
        while(current.data != value){
            if(current.next == null){
                return false;
            }else{
                previous = current;
                current = current.next;
            }
        }
        //如果刪除的節(jié)點(diǎn)是第一個(gè)節(jié)點(diǎn)
        if(current == head){
            head = current.next;
            size--;
        }else{//刪除的節(jié)點(diǎn)不是第一個(gè)節(jié)點(diǎn)
            previous.next = current.next;
            size--;
        }
        return true;
    }
    
    //判斷鏈表是否為空
    public boolean isEmpty(){
        return (size == 0);
    }
    
    //顯示節(jié)點(diǎn)信息
    public void display(){
        if(size >0){
            Node node = head;
            int tempSize = size;
            if(tempSize == 1){//當(dāng)前鏈表只有一個(gè)節(jié)點(diǎn)
                System.out.println("["+node.data+"]");
                return;
            }
            while(tempSize>0){
                if(node.equals(head)){
                    System.out.print("["+node.data+"->");
                }else if(node.next == null){
                    System.out.print(node.data+"]");
                }else{
                    System.out.print(node.data+"->");
                }
                node = node.next;
                tempSize--;
            }
            System.out.println();
        }else{//如果鏈表一個(gè)節(jié)點(diǎn)都沒(méi)有厢塘,直接打印[]
            System.out.println("[]");
        }
        
    }

}

測(cè)試:

@Test
public void testSingleLinkedList(){
    SingleLinkedList singleList = new SingleLinkedList();
    singleList.addHead("A");
    singleList.addHead("B");
    singleList.addHead("C");
    singleList.addHead("D");
    //打印當(dāng)前鏈表信息
    singleList.display();
    //刪除C
    singleList.delete("C");
    singleList.display();
    //查找B
    System.out.println(singleList.find("B"));
}

打印結(jié)果:

image

②茶没、用單向鏈表實(shí)現(xiàn)棧

棧的pop()方法和push()方法,對(duì)應(yīng)于鏈表的在頭部刪除元素deleteHead()以及在頭部增加元素addHead()晚碾。

package com.ys.datastructure;

public class StackSingleLink {
    private SingleLinkedList link;
    
    public StackSingleLink(){
        link = new SingleLinkedList();
    }
    
    //添加元素
    public void push(Object obj){
        link.addHead(obj);
    }
    
    //移除棧頂元素
    public Object pop(){
        Object obj = link.deleteHead();
        return obj;
    }
    
    //判斷是否為空
    public boolean isEmpty(){
        return link.isEmpty();
    }
    
    //打印棧內(nèi)元素信息
    public void display(){
        link.display();
    }

}

4抓半、雙端鏈表

對(duì)于單項(xiàng)鏈表,我們?nèi)绻朐谖膊刻砑右粋€(gè)節(jié)點(diǎn)格嘁,那么必須從頭部一直遍歷到尾部笛求,找到尾節(jié)點(diǎn),然后在尾節(jié)點(diǎn)后面插入一個(gè)節(jié)點(diǎn)糕簿。這樣操作很麻煩探入,如果我們?cè)谠O(shè)計(jì)鏈表的時(shí)候多個(gè)對(duì)尾節(jié)點(diǎn)的引用,那么會(huì)簡(jiǎn)單很多懂诗。

image

注意和后面將的雙向鏈表的區(qū)別7渌浴!殃恒!

①植旧、雙端鏈表的具體實(shí)現(xiàn)

package com.ys.link;

public class DoublePointLinkedList {
    private Node head;//頭節(jié)點(diǎn)
    private Node tail;//尾節(jié)點(diǎn)
    private int size;//節(jié)點(diǎn)的個(gè)數(shù)
    
    private class Node{
        private Object data;
        private Node next;
        
        public Node(Object data){
            this.data = data;
        }
    }
    
    public DoublePointLinkedList(){
        size = 0;
        head = null;
        tail = null;
    }
    
    //鏈表頭新增節(jié)點(diǎn)
    public void addHead(Object data){
        Node node = new Node(data);
        if(size == 0){//如果鏈表為空,那么頭節(jié)點(diǎn)和尾節(jié)點(diǎn)都是該新增節(jié)點(diǎn)
            head = node;
            tail = node;
            size++;
        }else{
            node.next = head;
            head = node;
            size++;
        }
    }
    
    //鏈表尾新增節(jié)點(diǎn)
    public void addTail(Object data){
        Node node = new Node(data);
        if(size == 0){//如果鏈表為空离唐,那么頭節(jié)點(diǎn)和尾節(jié)點(diǎn)都是該新增節(jié)點(diǎn)
            head = node;
            tail = node;
            size++;
        }else{
            tail.next = node;
            tail = node;
            size++;
        }
    }
    
    //刪除頭部節(jié)點(diǎn)病附,成功返回true,失敗返回false
    public boolean deleteHead(){
        if(size == 0){//當(dāng)前鏈表節(jié)點(diǎn)數(shù)為0
            return false;
        }
        if(head.next == null){//當(dāng)前鏈表節(jié)點(diǎn)數(shù)為1
            head = null;
            tail = null;
        }else{
            head = head.next;
        }
        size--;
        return true;
    }
    //判斷是否為空
    public boolean isEmpty(){
        return (size ==0);
    }
    //獲得鏈表的節(jié)點(diǎn)個(gè)數(shù)
    public int getSize(){
        return size;
    }
    
    //顯示節(jié)點(diǎn)信息
    public void display(){
        if(size >0){
            Node node = head;
            int tempSize = size;
            if(tempSize == 1){//當(dāng)前鏈表只有一個(gè)節(jié)點(diǎn)
                System.out.println("["+node.data+"]");
                return;
            }
            while(tempSize>0){
                if(node.equals(head)){
                    System.out.print("["+node.data+"->");
                }else if(node.next == null){
                    System.out.print(node.data+"]");
                }else{
                    System.out.print(node.data+"->");
                }
                node = node.next;
                tempSize--;
            }
            System.out.println();
        }else{//如果鏈表一個(gè)節(jié)點(diǎn)都沒(méi)有侯繁,直接打印[]
            System.out.println("[]");
        }
    }

}

②胖喳、用雙端鏈表實(shí)現(xiàn)隊(duì)列

package com.ys.link;

public class QueueLinkedList {
    
    private DoublePointLinkedList dp;
    
    public QueueLinkedList(){
        dp = new DoublePointLinkedList();
    }
    public void insert(Object data){
        dp.addTail(data);
    }
    
    public void delete(){
        dp.deleteHead();
    }
    
    public boolean isEmpty(){
        return dp.isEmpty();
    }
    
    public int getSize(){
        return dp.getSize();
    }
    
    public void display(){
        dp.display();
    }
    
}

5、抽象數(shù)據(jù)類型(ADT)

在介紹抽象數(shù)據(jù)類型的時(shí)候贮竟,我們先看看什么是數(shù)據(jù)類型,聽(tīng)到這個(gè)詞较剃,在Java中我們可能首先會(huì)想到像 int,double這樣的詞咕别,這是Java中的基本數(shù)據(jù)類型,一個(gè)數(shù)據(jù)類型會(huì)涉及到兩件事:

①写穴、擁有特定特征的數(shù)據(jù)項(xiàng)

②惰拱、在數(shù)據(jù)上允許的操作

比如Java中的int數(shù)據(jù)類型,它表示整數(shù)啊送,取值范圍為:-2147483648~2147483647偿短,還能使用各種操作符,+馋没、-昔逗、*、/ 等對(duì)其操作篷朵。數(shù)據(jù)類型允許的操作是它本身不可分離的部分勾怒,理解類型包括理解什么樣的操作可以應(yīng)用在該類型上婆排。

那么當(dāng)年設(shè)計(jì)計(jì)算機(jī)語(yǔ)言的人,為什么會(huì)考慮到數(shù)據(jù)類型笔链?

我們先看這樣一個(gè)例子段只,比如,大家都需要住房子鉴扫,也都希望房子越大越好赞枕。但顯然,沒(méi)有錢(qián)坪创,考慮房子沒(méi)有意義炕婶。于是就出現(xiàn)了各種各樣的商品房,有別墅的误堡、復(fù)式的古话、錯(cuò)層的、單間的……甚至只有兩平米的膠囊房間锁施。這樣做的意義是滿足不同人的需要陪踩。

同樣,在計(jì)算機(jī)中悉抵,也存在相同的問(wèn)題肩狂。計(jì)算1+1這樣的表達(dá)式不需要開(kāi)辟很大的存儲(chǔ)空間,不需要適合小數(shù)甚至字符運(yùn)算的內(nèi)存空間姥饰。于是計(jì)算機(jī)的研究者們就考慮傻谁,要對(duì)數(shù)據(jù)進(jìn)行分類,分出來(lái)多種數(shù)據(jù)類型列粪。比如int审磁,比如float。

雖然不同的計(jì)算機(jī)有不同的硬件系統(tǒng)岂座,但實(shí)際上高級(jí)語(yǔ)言編寫(xiě)者才不管程序運(yùn)行在什么計(jì)算機(jī)上态蒂,他們的目的就是為了實(shí)現(xiàn)整形數(shù)字的運(yùn)算,比如a+b等费什。他們才不關(guān)心整數(shù)在計(jì)算機(jī)內(nèi)部是如何表示的钾恢,也不管CPU是如何計(jì)算的。于是我們就考慮鸳址,無(wú)論什么計(jì)算機(jī)瘩蚪、什么語(yǔ)言都會(huì)面臨類似的整數(shù)運(yùn)算,我們可以考慮將其抽象出來(lái)稿黍。抽象是抽取出事物具有的普遍性本質(zhì)疹瘦,是對(duì)事物的一個(gè)概括,是一種思考問(wèn)題的方式闻察。

抽象數(shù)據(jù)類型(ADT)是指一個(gè)數(shù)學(xué)模型及定義在該模型上的一組操作拱礁。它僅取決于其邏輯特征琢锋,而與計(jì)算機(jī)內(nèi)部如何表示和實(shí)現(xiàn)無(wú)關(guān)。比如剛才說(shuō)得整型呢灶,各個(gè)計(jì)算機(jī)吴超,不管大型機(jī)、小型機(jī)鸯乃、PC鲸阻、平板電腦甚至智能手機(jī),都有“整型”類型缨睡,也需要整形運(yùn)算鸟悴,那么整型其實(shí)就是一個(gè)抽象數(shù)據(jù)類型。

更廣泛一點(diǎn)的奖年,比如我們剛講解的棧和隊(duì)列這兩種數(shù)據(jù)結(jié)構(gòu)细诸,我們分別使用了數(shù)組和鏈表來(lái)實(shí)現(xiàn),比如棧陋守,對(duì)于使用者只需要知道pop()和push()方法或其它方法的存在以及如何使用即可震贵,使用者不需要知道我們是使用的數(shù)組或是鏈表來(lái)實(shí)現(xiàn)的。

ADT的思想可以作為我們?cè)O(shè)計(jì)工具的理念水评,比如我們需要存儲(chǔ)數(shù)據(jù)猩系,那么就從考慮需要在數(shù)據(jù)上實(shí)現(xiàn)的操作開(kāi)始,需要存取最后一個(gè)數(shù)據(jù)項(xiàng)嗎中燥?還是第一個(gè)寇甸?還是特定值的項(xiàng)?還是特定位置的項(xiàng)疗涉?回答這些問(wèn)題會(huì)引出ADT的定義拿霉,只有完整的定義了ADT后,才應(yīng)該考慮實(shí)現(xiàn)的細(xì)節(jié)咱扣。

這在我們Java語(yǔ)言中的接口設(shè)計(jì)理念是想通的友浸。

回到頂部

6、有序鏈表

前面的鏈表實(shí)現(xiàn)插入數(shù)據(jù)都是無(wú)序的偏窝,在有些應(yīng)用中需要鏈表中的數(shù)據(jù)有序,這稱為有序鏈表武学。

在有序鏈表中祭往,數(shù)據(jù)是按照關(guān)鍵值有序排列的。一般在大多數(shù)需要使用有序數(shù)組的場(chǎng)合也可以使用有序鏈表火窒。有序鏈表優(yōu)于有序數(shù)組的地方是插入的速度(因?yàn)樵夭恍枰苿?dòng))硼补,另外鏈表可以擴(kuò)展到全部有效的使用內(nèi)存,而數(shù)組只能局限于一個(gè)固定的大小中熏矿。

package com.ys.datastructure;

public class OrderLinkedList {
    private Node head;
    
    private class Node{
        private int data;
        private Node next;
        
        public Node(int data){
            this.data = data;
        }
    }

    public OrderLinkedList(){
        head = null;
    }
    
    //插入節(jié)點(diǎn)已骇,并按照從小打到的順序排列
    public void insert(int value){
        Node node = new Node(value);
        Node pre = null;
        Node current = head;
        while(current != null && value > current.data){
            pre = current;
            current = current.next;
        }
        if(pre == null){
            head = node;
            head.next = current;
        }else{
            pre.next = node;
            node.next = current;
        }
    }
    
    //刪除頭節(jié)點(diǎn)
    public void deleteHead(){
        head = head.next;
    }
    
    public void display(){
        Node current = head;
        while(current != null){
            System.out.print(current.data+" ");
            current = current.next;
        }
        System.out.println("");
    }
    
}

在有序鏈表中插入和刪除某一項(xiàng)最多需要O(N)次比較离钝,平均需要O(N/2)次,因?yàn)楸仨氀刂湵砩弦徊揭徊阶卟拍苷业秸_的插入位置褪储,然而可以最快速度刪除最值卵渴,因?yàn)橹恍枰獎(jiǎng)h除表頭即可,如果一個(gè)應(yīng)用需要頻繁的存取最小值鲤竹,且不需要快速的插入浪读,那么有序鏈表是一個(gè)比較好的選擇方案。比如優(yōu)先級(jí)隊(duì)列可以使用有序鏈表來(lái)實(shí)現(xiàn)辛藻。

7碘橘、有序鏈表和無(wú)序數(shù)組組合排序

比如有一個(gè)無(wú)序數(shù)組需要排序,前面我們?cè)谥v解冒泡排序吱肌、選擇排序痘拆、插入排序這三種簡(jiǎn)單的排序時(shí),需要的時(shí)間級(jí)別都是O(N2)氮墨。

現(xiàn)在我們講解了有序鏈表之后纺蛆,對(duì)于一個(gè)無(wú)序數(shù)組,我們先將數(shù)組元素取出勇边,一個(gè)一個(gè)的插入到有序鏈表中犹撒,然后將他們從有序鏈表中一個(gè)一個(gè)刪除,重新放入數(shù)組粒褒,那么數(shù)組就會(huì)排好序了识颊。和插入排序一樣,如果插入了N個(gè)新數(shù)據(jù)奕坟,那么進(jìn)行大概N2/4次比較祥款。但是相對(duì)于插入排序,每個(gè)元素只進(jìn)行了兩次排序月杉,一次從數(shù)組到鏈表刃跛,一次從鏈表到數(shù)組,大概需要2*N次移動(dòng)苛萎,而插入排序則需要N2次移動(dòng)桨昙,

效率肯定是比前面講的簡(jiǎn)單排序要高,但是缺點(diǎn)就是需要開(kāi)辟差不多兩倍的空間腌歉,而且數(shù)組和鏈表必須在內(nèi)存中同時(shí)存在蛙酪,如果有現(xiàn)成的鏈表可以用,那么這種方法還是挺好的翘盖。

8桂塞、雙向鏈表

我們知道單向鏈表只能從一個(gè)方向遍歷,那么雙向鏈表它可以從兩個(gè)方向遍歷馍驯。

image

具體代碼實(shí)現(xiàn):

package com.ys.datastructure;

public class TwoWayLinkedList {
    private Node head;//表示鏈表頭
    private Node tail;//表示鏈表尾
    private int size;//表示鏈表的節(jié)點(diǎn)個(gè)數(shù)
    
    private class Node{
        private Object data;
        private Node next;
        private Node prev;
        
        public Node(Object data){
            this.data = data;
        }
    }
    
    public TwoWayLinkedList(){
        size = 0;
        head = null;
        tail = null;
    }
    
    //在鏈表頭增加節(jié)點(diǎn)
    public void addHead(Object value){
        Node newNode = new Node(value);
        if(size == 0){
            head = newNode;
            tail = newNode;
            size++;
        }else{
            head.prev = newNode;
            newNode.next = head;
            head = newNode;
            size++;
        }
    }
    
    //在鏈表尾增加節(jié)點(diǎn)
    public void addTail(Object value){
        Node newNode = new Node(value);
        if(size == 0){
            head = newNode;
            tail = newNode;
            size++;
        }else{
            newNode.prev = tail;
            tail.next = newNode;
            tail = newNode;
            size++;
        }
    }
    
    //刪除鏈表頭
    public Node deleteHead(){
        Node temp = head;
        if(size != 0){
            head = head.next;
            head.prev = null;
            size--;
        }
        return temp;
    }
    
    //刪除鏈表尾
    public Node deleteTail(){
        Node temp = tail;
        if(size != 0){
            tail = tail.prev;
            tail.next = null;
            size--;
        }
        return temp;
    }
    
    //獲得鏈表的節(jié)點(diǎn)個(gè)數(shù)
    public int getSize(){
        return size;
    }
    //判斷鏈表是否為空
    public boolean isEmpty(){
        return (size == 0);
    }
    
    //顯示節(jié)點(diǎn)信息
    public void display(){
        if(size >0){
            Node node = head;
            int tempSize = size;
            if(tempSize == 1){//當(dāng)前鏈表只有一個(gè)節(jié)點(diǎn)
                System.out.println("["+node.data+"]");
                return;
            }
            while(tempSize>0){
                if(node.equals(head)){
                    System.out.print("["+node.data+"->");
                }else if(node.next == null){
                    System.out.print(node.data+"]");
                }else{
                    System.out.print(node.data+"->");
                }
                node = node.next;
                tempSize--;
            }
            System.out.println();
        }else{//如果鏈表一個(gè)節(jié)點(diǎn)都沒(méi)有阁危,直接打印[]
            System.out.println("[]");
        }
        
    }
}

我們也可以用雙向鏈表來(lái)實(shí)現(xiàn)雙端隊(duì)列玛痊,這里就不做具體代碼演示了。

9狂打、總結(jié)

上面我們講了各種鏈表擂煞,每個(gè)鏈表都包括一個(gè)LinikedList對(duì)象和許多Node對(duì)象,LinkedList對(duì)象通常包含頭和尾節(jié)點(diǎn)的引用菱父,分別指向鏈表的第一個(gè)節(jié)點(diǎn)和最后一個(gè)節(jié)點(diǎn)颈娜。而每個(gè)節(jié)點(diǎn)對(duì)象通常包含數(shù)據(jù)部分data,以及對(duì)上一個(gè)節(jié)點(diǎn)的引用prev和下一個(gè)節(jié)點(diǎn)的引用next浙宜,只有下一個(gè)節(jié)點(diǎn)的引用稱為單向鏈表官辽,兩個(gè)都有的稱為雙向鏈表。next值為null則說(shuō)明是鏈表的結(jié)尾粟瞬,如果想找到某個(gè)節(jié)點(diǎn)同仆,我們必須從第一個(gè)節(jié)點(diǎn)開(kāi)始遍歷,不斷通過(guò)next找到下一個(gè)節(jié)點(diǎn)裙品,直到找到所需要的俗批。棧和隊(duì)列都是ADT,可以用數(shù)組來(lái)實(shí)現(xiàn)市怎,也可以用鏈表實(shí)現(xiàn)岁忘。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市区匠,隨后出現(xiàn)的幾起案子干像,更是在濱河造成了極大的恐慌,老刑警劉巖驰弄,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件麻汰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡戚篙,警方通過(guò)查閱死者的電腦和手機(jī)五鲫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)岔擂,“玉大人位喂,你說(shuō)我怎么就攤上這事÷伊椋” “怎么了忆某?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)阔蛉。 經(jīng)常有香客問(wèn)我,道長(zhǎng)癞埠,這世上最難降的妖魔是什么状原? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任聋呢,我火速辦了婚禮,結(jié)果婚禮上颠区,老公的妹妹穿的比我還像新娘削锰。我一直安慰自己,他們只是感情好毕莱,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布器贩。 她就那樣靜靜地躺著,像睡著了一般朋截。 火紅的嫁衣襯著肌膚如雪蛹稍。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,036評(píng)論 1 285
  • 那天部服,我揣著相機(jī)與錄音唆姐,去河邊找鬼。 笑死廓八,一個(gè)胖子當(dāng)著我的面吹牛奉芦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播剧蹂,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼声功,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了宠叼?” 一聲冷哼從身側(cè)響起先巴,我...
    開(kāi)封第一講書(shū)人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎车吹,沒(méi)想到半個(gè)月后筹裕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡窄驹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年朝卒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乐埠。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡抗斤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出丈咐,到底是詐尸還是另有隱情瑞眼,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布棵逊,位于F島的核電站伤疙,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜徒像,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一黍特、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锯蛀,春花似錦灭衷、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至劈愚,卻和暖如春瞳遍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背造虎。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工傅蹂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人算凿。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓份蝴,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親氓轰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子婚夫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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