附1 环形链表

149 阅读2分钟

附录工具1

一个链表,判断链表中是否有环。

思路: 设定两个指针,fast 步长为2,slow 步长为1,遍历,
从同一点出发,如果两个指针相遇,那么表示这个链表有环。
如果没有环,那么fast 先达到 NULL

快慢指针相遇时的循环次数等于环的长度。

如何找出 环链表的入口

    思路: 快慢指针相遇点 到环入口的距离 = 链表起始点到环 入口的距离
        

如何求解环的长度

    思路:当两个指针相遇Z时,此时slow走过的路径为 a + bfast走过的路径为 a+b+c+b, 因为fast步长为 slow的两边,所以 2a+b)=a+b+c+b

所以 a = c, 环的长度为 b + c,也就是 a+b,即slow走过的步长如何判断两个链表是否相交

    思路: 如果两个链表相交,那么这两个链表尾节点 一定相同,直接判断尾节点是否相同即可,

1 例子:环形链表可以拆分为两个Y链表。

环形链表用例: pos 表示 链表尾部节点 执行该链表的 哪一个节点:

		输入:
		[3,2,0,-4]    pos = 1  # 表示1个环 -4 与 2相 链
			|____|

		输出:
		tail connects to node index 1

		输入:
			[1, 3, 4]  pos =0   #  表示 4 与 1 首尾相连
			|_____|
		输出:
			tail connects to node index 0

		输入:
			[1, 2]  pos = 0  # 表示 2 与 1 连
			|__|
		输出:
			tail connects to node index 0

		输入:
			[-1]
			-1  # 表示没有 环
		输出:
			null
                            

2 实现

我们使用双向链表实现环形链接。 首先定义链表的每个节点

   type Node struct {
        Number int
        Prev   *Node
        Next   *Node
}

  type Doublist struct {
        Lens int
        Head *Node
        Tail *Node
}

func MakeDlist() *Doublist {
        return &Doublist{}
}

实现对节点的有序放入

func (th *Doublist) Pushback(n *Node) bool {
        if n == nil {
                return false
        }
        currentNode := th.Head
        if currentNode == nil {

                return th.NewNodeList(n)
        } else {
                inDex, insertNode := th.Lesseq(n)
                if inDex == 0 {
                        return th.PushHead(n)
                } else if inDex == (th.Lens-1) && insertNode == nil {
                        return th.Append(n)
                } 

                n.Next = insertNode
                n.Prev = insertNode.Prev
                if insertNode.Prev != nil {
                        insertNode.Prev.Next = n
                }

                insertNode.Prev = n
                th.Lens += 1
                return true
        }
}

显示链表的值

func (th *Doublist) Display() {

        node := th.Head
        t := 0
        Logg.Println(node.Number)
        for node != nil {
                t += 1
                if t >= th.Lens {
                        break
                }

                node = node.Next
                Logg.Println(node.Number)
        }

        Logg.Println("length:", th.Lens)
}

然后定义环形链表

   type CycleLinked struct {
        Size  int
        Items *Doublist
}

链表缓存通道

type MyChan struct {
        Read  <-chan *Node
        Input chan<- *Node
}

添加多个节点到链表

func (cl *CycleLinked) SetItems(n int) *CycleLinked {
        if n <= cl.Size {
                cl.Items = MakeDlist()
                for i := 0; i < n; i++ {
                        cl.Items.Pushback(&Node{Number: i})
                }
        }

        return cl

}

使用有环链表,创建 空链表,填入数字

        tLinked := MakeEmptyLinked(8)
        
        numberC := tLinked.SetItems(tLinked.Size)

        cNode := numberC.Items.Head
        for cNode != nil {
                Logg.Printf("%+v\n", cNode)
                cNode = cNode.Next
        }
}

3 小结

该文本为工具使用解说。本部分完。

源代码地址:

 https://github.com/hahamx/utools/blob/main/utils/circled/main.go