鏈表(Java)

部分轉(zhuǎn)自http://www.itdecent.cn/p/6782f3d96471

單鏈表

什么是單鏈表

鏈表(Linked list)是一種線性表,但是并不會(huì)按線性的順序存儲(chǔ)數(shù)據(jù),而是在每一個(gè)節(jié)點(diǎn)里存到下一個(gè)節(jié)點(diǎn)的引用(Pointer)。鏈表并不像數(shù)組那樣將數(shù)組存儲(chǔ)在一個(gè)連續(xù)的內(nèi)存地址空間里,所以較之?dāng)?shù)組來(lái)說(shuō)這是一個(gè)優(yōu)勢(shì)。

單鏈表的特點(diǎn)

  • 鏈表增刪元素的時(shí)間復(fù)雜度為O(1),查找一個(gè)元素的時(shí)間復(fù)雜度為 O(n);
  • 單鏈表不用像數(shù)組那樣預(yù)先分配存儲(chǔ)空間的大小,避免了空間浪費(fèi);
  • 單鏈表不能進(jìn)行回溯操作,如:只知道鏈表的頭節(jié)點(diǎn)的時(shí)候無(wú)法快讀快速鏈表的倒數(shù)第幾個(gè)節(jié)點(diǎn)的值。

單鏈表的基本操作

獲取單鏈表的長(zhǎng)度

對(duì)于一個(gè)鏈表的長(zhǎng)度我們只能一次去遍歷鏈表的節(jié)點(diǎn),直到找到某個(gè)節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)為空的時(shí)候得到鏈表的總長(zhǎng)度:

public int getLength(Node head){
    if(head == null){
        return 0;
    }
    int len = 0;
    while(head != null){
        len++;
        head = head.next;
    }  
    return len;  
}
查詢指定索引的節(jié)點(diǎn)值或指定節(jié)點(diǎn)值的索引

查詢指定索引的節(jié)點(diǎn)值:

public int getValueOfIndex(Node head, int index) throws Exception {
    if (index < 0 || index >= getLength(head)) {
        throw new Exception("角標(biāo)越界!");
    }
    if (head == null) {
        throw new Exception("當(dāng)前鏈表為空!");
    }
    Node targetHead = head;
    while (targetHead.next != null && index > 0) {
        targetHead = targetHead.next;
        index--;
    }
    return targetHead.value;
}

查詢指定節(jié)點(diǎn)值的索引:

public int getNodeIndex(Node head, int value) {
    int index = -1;
    Node targetHead= head;
    while (targetHead!= null) {
        index++;
        if (targetHead.value == value) {
            return index;
        }
        targetHead= targetHead.next;
    }
    return -1;
}
添加一個(gè)元素

1、在已有鏈表頭部插入一個(gè)節(jié)點(diǎn)

public Node addAtHead(Node head, int value){
    Node newHead = new Node(value);
    newHead.next = head;
    return newHead;
}

2、在已有鏈表的尾部插入一個(gè)節(jié)點(diǎn):

public void addAtTail(Node head, int value){
    Node node = new Node(value);
    Node targetHead= head;
    while( targetHead.next != null){
        targetHead= targetHead.next;
    }
    targetHead.next = node;   
}

3、在指定位置添加一個(gè)節(jié)點(diǎn)

public Node insertElement(Node head, int value, int index) throws Exception {
   //為了方便這里我們假設(shè)知道鏈表的長(zhǎng)度
   int length = getLength(head);
   if (index < 0 || index >= length) {
       throw new Exception("角標(biāo)越界!");
   }
   if (index == 0) {
       return addAtHead(head, value);
   } 
   else if (index == length - 1) {
       addAtTail(head, value);
   }
   else {
       Node pre = head;
       Node cur = head.next;
       while (pre != null && index > 1) {
           pre = pre.next;
           cur = cur.next;
           index--;
       }  //循環(huán)結(jié)束后 pre 保存的是索引的上一個(gè)節(jié)點(diǎn) 而 cur 保存的是索引值當(dāng)前的節(jié)點(diǎn)
       Node node = new Node(value);
       pre.next = node;
       node.next = cur;
   }
   return head;
}

在指定位置添加一個(gè)節(jié)點(diǎn),首先我們應(yīng)該找到這個(gè)索引所在的節(jié)點(diǎn)的前一個(gè),以及該節(jié)點(diǎn),分別記錄這兩個(gè)節(jié)點(diǎn),然后將索引所在節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)的 next 指針指向新節(jié)點(diǎn),然后將新節(jié)點(diǎn)的 next 指針指向插入節(jié)點(diǎn)即可。與其他元素并沒(méi)有什么關(guān)系,所以單鏈表插入一個(gè)節(jié)點(diǎn)時(shí)間復(fù)雜度為 O(1)。

而數(shù)組插入元素就不一樣了如果將一個(gè)元素插入數(shù)組的指定索引位置,那么該索引位置以后元素的索引位置(內(nèi)存地址)都將發(fā)生變化,所以一個(gè)數(shù)組的插入一個(gè)元素的時(shí)間復(fù)雜度為 O(n);所以鏈表相對(duì)于數(shù)組插入的效率要高一些,刪除同理。

刪除一個(gè)元素

1、 刪除頭部節(jié)點(diǎn)

public Node deleteHead(Node head) throws Exception {
    if (head == null) {
        throw new Exception("當(dāng)前鏈表為空!");
    }
    return head.next;
}

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

public void deleteTail(Node head) throws Exception {
    if (head == null) {
        throw new Exception("當(dāng)前鏈表為空!");
    }
    Node targetHead = head;
    while (targetHead.next != null && targetHead.next.next != null) {
        targetHead= targetHead.next;
    }
    targetHead.next = null;
}

3、 刪除指定索引的節(jié)點(diǎn):

public Node deleteElement(Node head, int index) throws Exception {
    int size = getLength(head);
    if (index < 0 || index >= size) {
        throw new Exception("角標(biāo)越界!");
    }
    if (index == 0) {
        return deleteHead(head);
    } 
    else if (index == size - 1) {
        deleteTail(head);
    }
    else {
        Node pre = head;
        while (pre.next != null && index > 1) {
            pre = pre.next;
            index--;
        }
        //循環(huán)結(jié)束后 pre 保存的是索引的上一個(gè)節(jié)點(diǎn) 將其指向索引的下一個(gè)元素
        if (pre.next != null) {
            pre.next = pre.next.next;
        }
    }
    return head;
}

由單鏈表的增加刪除可以看出,鏈表的想要對(duì)指定索引進(jìn)行操作(增加,刪除),的時(shí)候必須獲取該索引的前一個(gè)元素。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容