單鏈表 常用操作(golang)

(單鏈表備忘記錄)
知識點:

  1. 單鏈表結(jié)構(gòu)
  2. 創(chuàng)建鏈表方法
    1. 頭插法創(chuàng)建
    2. 尾插法創(chuàng)建
  3. 遍歷鏈表
  4. 逆序反轉(zhuǎn)鏈表
    1. 迭代
    2. 遞歸
    3. 頭插法
    4. 就地逆置
  5. 判斷鏈表中是否有環(huán)
  6. 鏈表中環(huán)的入口點
  7. 鏈表中環(huán)的長度
  8. 鏈表總長度


1. 單鏈表結(jié)構(gòu)

data. 數(shù)據(jù)
next. 指向下一個鏈表節(jié)點的指針

type Node struct {
    data int
    next *Node
}

2. 創(chuàng)建鏈表方法

簡單的可以一行行敲著創(chuàng)建,先創(chuàng)建node1,然后node2,
然后鏈起來node1.next=&node2
1. 頭插法創(chuàng)建

/*頭插法 創(chuàng)建鏈表*/
func CreateNodeInsterOnHead(listData []int) *Node {
    if len(listData) == 0 {
        return &Node{data: 0}
    }
    head := &Node{data: listData[0]}
    for _, v := range listData[1:] {
        node := &Node{data: v}
        node.next = head //新節(jié)點的next指向頭head
        head = node//頭head換成新節(jié)點
    }
    return head
}

傳入 「1 2 3 4 5 6 7 8 9 10」
輸出 「10 9 8 7 6 5 4 3 2 1」
2. 尾插法創(chuàng)建

/*尾插法創(chuàng)建鏈表*/
func CreateNodeInsterOnTail(listData []int) *Node {
    if len(listData) == 0 {
        return &Node{data: 0}
    }
    head := &Node{data: listData[0]}
    end := head //end 記錄鏈表的尾,不斷向end后插入新節(jié)點
    for _, v := range listData[1:] {
        end.next = &Node{data: v}
        end = end.next //移動end指針,指向新的尾節(jié)點
    }
    return head
}

傳入 「1 2 3 4 5 6 7 8 9 10」
輸出 「1 2 3 4 5 6 7 8 9 10」

3. 遍歷鏈表

func printNode(node *Node) {
    if node == nil || node.next == nil {
        return
    }
    cur := node
    for cur != nil {
        fmt.Printf("%d ", cur.data)
        cur = cur.next
    }
}

4. 逆序反轉(zhuǎn)鏈表

4.1 迭代
func ReverseNode1(head *Node) *Node {
    if head == nil || head.next == nil {
        return head
    }
    var prev *Node = nil
    var cur *Node = head
    var end *Node = head.next
    for {
        cur.next = prev //當(dāng)前結(jié)點指向前一個節(jié)點
        if end == nil {
            break
        }
        prev = cur     //指針后移
        cur = end      //指針后移,處理下一個節(jié)點
        end = end.next //temp作為中間節(jié)點,記錄當(dāng)前結(jié)點的下一個節(jié)點的位置
    }
    head = cur
    return head
}

4.2 遞歸
func ReverseNode2(head *Node) *Node {
    if head == nil || head.next == nil {//遞歸的出口
        return head
    } else {
        //一直遞歸,找到鏈表中最后一個節(jié)點
        new_head := ReverseNode2(head.next)

        //當(dāng)逐層退出時,new_head 的指向都不變,一直指向原鏈表中最后一個節(jié)點;
        //遞歸每退出一層,函數(shù)中 head 指針的指向都會發(fā)生改變,都指向上一個節(jié)點。

        //每退出一層,都需要改變 head->next 節(jié)點指針域的指向,同時令 head 所指節(jié)點的指針域為 NULL。
        head.next.next = head
        head.next = nil
        //每一層遞歸結(jié)束,都要將新的頭指針返回給上一層。由此,即可保證整個遞歸過程中,能夠一直找得到新鏈表的表頭。
        return new_head
    }
}
4.3 頭插法
func ReverseNode3(head *Node) *Node {
    var new_head *Node = nil
    var temp *Node = nil
    if head == nil || head.next == nil {
        return head
    }
    for head != nil {
        temp = head
        //將 temp 從 head 中摘除
        head = head.next
        //將 temp 插入到 new_head 的頭部
        temp.next = new_head
        new_head = temp
    }
    return new_head
}
4.4 就地逆置
func ReverseNode4(head *Node) *Node {
    var beg *Node = nil
    var end *Node = nil
    if head == nil || head.next == nil {
        return head
    }
    beg = head
    end = head.next
    for end != nil {
        //將 end 從鏈表中摘除
        beg.next = end.next
        //將 end 移動至鏈表頭
        end.next = head
        head = end
        //調(diào)整 end 的指向,另其指向 beg 后的一個節(jié)點,為反轉(zhuǎn)下一個節(jié)點做準(zhǔn)備
        end = beg.next
    }
    return head
}

5. 判斷鏈表中是否有環(huán)

快慢指針

/*
* 鏈表是否有環(huán)
* is 是否
* meet 有環(huán)是返回快慢指針的相遇節(jié)點
*/
func isRingLinkNode(head *Node) (is bool, meet *Node) {
    slow := head
    fast := head
    for fast != nil && fast.next != nil {
        slow = slow.next
        fast = fast.next.next
        if slow == fast {
            return true, slow
        }
    }
    return false, nil
}

6. 鏈表中環(huán)的入口點

func findRingeEntry(head *Node) *Node {
    slow := head
    fast := head
    for fast != nil && fast.next != nil {
        slow = slow.next
        fast = fast.next.next
        if slow == fast {
            break
        }
    }

    if fast == nil || fast.next == nil {
        return nil
    }
    slow = head //慢指針重新指向頭節(jié)點
    for slow != fast {
        slow = slow.next
        fast = fast.next
    }
    return slow
}

相遇后,slow繼續(xù)一次移動一個節(jié)點,新另一node從鏈表頭開始一次移動一個節(jié)點。

7. 鏈表中環(huán)的長度

//計算單鏈表環(huán)的長度
func ringLength(head *Node) int {
    //首先通過上面的方法判斷,鏈表是否有環(huán),并返回快慢指針的相遇點
    is, meet := isRingLinkNode(head)
    if is == false {
        return 0 //沒有環(huán),則直接返回
    }
    tmp := meet //tmp 停留在相遇點不再移動
    meet = meet.next
    len := 1
    for tmp != meet {
        len++
        meet = meet.next
    }
    return len
}

先用快慢指針相遇,相遇后記錄相遇點,然后繼續(xù)next向下走并記錄走了幾步,
再次相遇時即環(huán)長度。

8. 鏈表總長度

總長度 = 頭到入口點長度 + 環(huán)到長度

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

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

  • 搞懂單鏈表常見面試題 Hello 繼上次的 搞懂基本排序算法,這個一星期,我總結(jié)了,我所學(xué)習(xí)和思考的單鏈表基礎(chǔ)知識...
    醒著的碼者閱讀 4,732評論 1 45
  • 涉及到單鏈表的基本操作有如下: int initList(linkList *);//初始化一個單鏈表,具有頭指針...
    keeeeeenon閱讀 2,133評論 0 1
  • 前言 本文是題主準(zhǔn)備面試時記錄下的筆記整理而來,稍顯粗陋,還請各位擼友勿噴哈! Topic 目錄數(shù)組字符串鏈表二叉...
    rh_Jameson閱讀 1,666評論 1 10
  • 單鏈表 單鏈表問題與思路 找出單鏈表的倒數(shù)第K個元素(僅允許遍歷一遍鏈表)使用指針追趕的方法。定義兩個指針fast...
    wxkkkkk閱讀 649評論 0 0
  • 表情是什么,我認為表情就是表現(xiàn)出來的情緒。表情可以傳達很多信息。高興了當(dāng)然就笑了,難過就哭了。兩者是相互影響密不可...
    Persistenc_6aea閱讀 129,613評論 2 7

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