- 前言
- Go 与操作系统
- Go 内部机制
- Go 基本数据类型
- 4 组合类型的使用
- 5 数据结构
- 6 Go package 中不为人知的知识
- 7 反射和接口
- 8 Go UNIX 系统编程
- 08.1 关于 UNIX 进程
- 08.2 flag 包
- 8.2 flag 包
- 08.3 io.Reader 和 io.Writer 接口
- 08.4 bufio 包
- 08.5 读取文本文件
- 08.6 从文件中读取所需的数据量
- 08.7 为什么我们使用二进制格式
- 08.8 读取 CSV 文件
- 08.9 写入文件
- 08.10 从磁盘加载和保存数据
- 08.11 再看strings包
- 08.12 关于bytes包
- 08.13 文件权限
- 08.14 处理 Unix 信号
- 08.15 Unix 管道编程
- 08.16 遍历目录树
- 08.17 使用 ePBF
- 08.18 关于 syscall.PtraceRegs
- 08.19 跟踪系统调用
- 08.20 User ID 和 group ID
- 08.21 其他资源
- 08.22 练习
- 08.23 总结
- 9 并发 Goroutines、Channel 和 Pipeline
- 10 Go 并发-进阶讨论
- 11 代码测试、优化及分析
- 12 Go 网络编程基础
- 13 网络编程 - 构建服务器与客户端
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
05.6.1 Go 语言实现双向链表
Go 语言实现双向链表
实现了双向链表的 Go 程序是 doublyLList.go
,我们将分为五个部分来介绍。双向链表背后的基本思想和单向链表相同。不过由于双向链表中每个节点都有两个指针,所以操作更冗杂。
doublyLList.go
的第一部分如下:
package main
import (
"fmt"
)
type Node struct {
Value int
Previous *Node
Next *Node
}
这部分中使用 Go 的结构体定义了双向链表的节点。不过这次的 struct
中有两个指针字段,原因就不必多说了。
doublyLList.go
的第二部分包含如下的 Go 代码:
func addNode(t *Node, v int) int {
if root == nil {
t = &Node{v, nil, nil}
root = t
return 0
}
if v == t.Value {
fmt.Println("Node already exists:", v)
return -1
}
if t.Next == nil {
temp := t
t.Next = &Node{v, temp, nil}
return -2
}
return addNode(t.Next, v)
}
就像单向链表中一样,新的节点都被添加在当前双向链表的末端。这并不是强制性的,你也可以选择对这个双向链表进行排序。
doublyLList.go
的第三部分如下:
func traverse(t *Node) {
if t == nil {
fmt.Println("-> Empty list!")
return
}
for t != nil {
fmt.Printf("%d -> ", t.Value)
t = t.Next
}
fmt.Println()
}
func reverse(t *Node) {
if t == nil {
fmt.Println("-> Empty list!")
return
}
temp := t
for t != nil {
temp = t
t = t.Next
}
for temp.Previous != nil {
fmt.Printf("%d -> ", temp.Value)
temp = temp.Previous
}
fmt.Printf("%d -> ", temp.Value)
fmt.Println()
}
这是 traverse()
和 reverse()
函数的 Go 代码。traverse()
的实现和 linkedList.go
中的一样。但是 reverse()
背后的逻辑很有趣。因为没有指向双向链表尾节点的指针,所以我们必须先从头向后访问,直到找到尾节点,之后才能反向遍历所有的节点。
doublyLList.go
的第四部分包含如下的 Go 代码:
func size(t *Node) int {
if t == nil {
fmt.Println("-> Empty list!")
return 0
}
n := 0
for t != nil {
n++
t = t.Next
}
return n
}
func lookupNode(t *Node, v int) bool {
if root == nil {
return false
}
if v == t.Value {
return true
}
if t.Next == nil {
return false
}
return lookupNode(t.Next, v)
}
doublyLList.go
的最后一个代码段包含如下的 Go 代码:
var root = new(Node)
func main() {
fmt.Println(root)
root = nil
traverse(root)
addNode(root, 1)
addNode(root, 1)
traverse(root)
addNode(root, 10)
addNode(root, 5)
addNode(root, 0)
addNode(root, 0)
traverse(root)
addNode(root, 100)
fmt.Println("Size:", size(root))
traverse(root)
reverse(root)
}
执行 doublyLList.go
,你将得到如下输出:
$ go run doublyLList.go
&{0 <nil> <nil>}
-> Empty list!
Node already exists: 1
1 ->
Node already exists: 0
1 -> 10 -> 5 -> 0 ->
Size: 5
1 -> 10 -> 5 -> 0 -> 100 ->
100 -> 0 -> 5 -> 10 -> 1 ->
如你所见,reverse()
函数效果很好!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论