在Golang的数据结构中,一个链表是包含节点的,它包含两个字段:一个下一个指针和列表的数据。我们将使用两种方法来检测链表中的循环。在第一个方法中,将使用双指针方法,在第二个例子中,使用地图来执行程序。让我们通过这些例子来了解执行情况。
方法1:使用双指针方法
在这种方法中,使用一个低指针和一个高指针来遍历链接列表。当高指针每次前进两步时,低指针每次前进一步。如果链接列表包含一个循环,高指针将最终超过低指针,并且它们都将指向同一个节点。考虑到在这个例子中链接列表包含一个循环,我们返回 true。
算法
- 第1步 – 创建一个包main,并在程序中声明fmt(format package)包,其中main产生可执行代码,fmt帮助格式化输入和输出。
-
第2步 – 创建一个Node结构,其值为int类型,Next为Node类型。
-
第3步– 创建一个函数has_loop,并在该函数中建立两个指针–low和high,并将它们都设置为指向链表的头部。
-
第4步 – 高指针每次移动两步,而低指针每次移动一步。
-
第5步– 在有循环的链接列表中,高指针最终会超过低指针,然后两个点都会指向同一个节点。
-
第6步– 在这种情况下返回真,因为链接列表包含一个循环。
-
第7步– 如果没有循环,快速指针将最终到达链表的末端,在这种情况下我们可以返回false。
-
第8步 – 使用 fmt.Println() 函数执行打印语句,其中 ln 表示新行。
-
第9步 – “双指针策略 “或 “龟兔赛跑算法 “是这个公式的其他名称。鉴于只需要两个指针,它的空间复杂度为O(1),时间复杂度为O(n),其中n是链接列表中的节点数。
例子
在这个例子中,我们将使用双指针方法来执行程序。
package main
import "fmt"
type Node struct {
Value int
Next *Node
}
func has_loop(head *Node) bool {
low := head
high := head
for high != nil && high.Next != nil {
low = low.Next
high = high.Next.Next
if low == high {
return true
}
}
return false
}
func main() {
head := &Node{Value: 1} //initialize the linked list with values
node2 := &Node{Value: 2}
node3 := &Node{Value: 3}
node4 := &Node{Value: 4}
head.Next = node2 //point to the elements using linked list
node2.Next = node3
node3.Next = node4
node4.Next = node2
fmt.Println("Does this linked list has loop?")
fmt.Println(has_loop(head)) // Output: true
}
输出
Does this linked list has loop?
true
方法2:在Golang中使用地图
在这个实现中,被访问的节点被记录在一个地图上。我们确定链表中的一个节点是否在之前被访问过,对于里面的每个节点。如果有,我们就返回true,因为链接列表包含一个循环。如果我们到达链接列表的末尾而没有遇到被访问的节点,我们返回false。
算法
- 第1步 – 创建一个包main,并在程序中声明fmt(format package)包,其中main产生可执行代码,fmt帮助格式化输入和输出。
-
第2步 – 创建一个Node结构,其值为int类型,Next为Node类型。
-
第3步 – 创建一个函数has_loop,并在该函数中制作一个地图来存储你所访问的节点。
-
第4步– 当你在链表中移动时检查每个节点,从头部开始。
-
第5步– 验证每个节点在地图上的存在,看它以前是否被访问过。
-
第6步 – 如果一个节点以前被访问过,则返回true,因为链表有一个循环。
-
第7步– 如果当我们到达链表的末端时,没有被访问的节点,则返回false。
-
第8步– 这种方法采用了一个地图来存储被访问的节点,其结果是时间复杂度为O(n),空间复杂度为O(n),其中n是链接列表中的节点数。
例子
在这个例子中,我们将使用地图来存储访问的节点。
package main
import "fmt"
type Node struct {
Value int
Next *Node
}
func has_loop(head *Node) bool {
Map := make(map[*Node]bool) //create a map to store visited nodes.
for current := head; current != nil; current = current.Next {
if Map[current] {
return true
}
Map[current] = true
}
return false
}
func main() {
head := &Node{Value: 10} //fill the linked list with elements
node2 := &Node{Value: 20}
node3 := &Node{Value: 30}
node4 := &Node{Value: 40}
head.Next = node2
node2.Next = node3
node3.Next = node4
node4.Next = node2
fmt.Println("Does this linked list has loop?")
fmt.Println(has_loop(head)) // Output: true
}
输出
Does this linked list has loop?
true
结论
我们用两种方法执行了检测链接列表中是否有循环的程序。在第一种方法中,我们使用了双指针方法,在第二个例子中,我们使用地图来存储被访问的节点。