08 | container包中的那些容器
该思维导图由 AI 生成,仅供参考
- 深入了解
- 翻译
- 解释
- 总结
本文深入讨论了Go语言中的`container/list`代码包提供的链表实现,重点介绍了如何使用`List`的方法来操作链表中的元素以及对自定义`Element`值的处理。文章指出了自定义的`Element`值并不直接影响链表的操作,同时解释了链表的特性和`Ring`与`List`的区别。此外,还对`Ring`和`List`在表示方式、初始化、性能和方法方面的差异进行了比较。最后,文章引导读者思考`container/ring`包中的循环链表的适用场景以及`container/heap`包中的堆的适用场景。通过讨论链表的操作方法和特点,本文帮助读者更好地理解`container/list`代码包中链表的使用方法和与其他数据结构的区别。 在文章中,还对切片与数组的比较进行了介绍。切片虽然具有占用内存少、创建便捷等特点,但在删除元素和频繁扩容时会带来一些问题,如元素复制、内存浪费等。同时,文章也提到了链表所占用的内存空间通常比包含相同元素的数组所占内存大得多,但链表的结构相对简单。通过对比,读者可以更好地理解切片、数组和链表的特点和适用场景。 总的来说,本文通过深入讨论链表的操作方法和特点,以及对切片与数组的比较,帮助读者更好地理解Go语言中不同数据结构的使用方法和适用场景。
《Go 语言核心 36 讲》,新⼈⾸单¥59
全部留言(40)
- 最新
- 精选
- louis郝老师,这里不太理解什么叫“自己生成的Element类型值”?把自己生成的Element类型值传给链表——这个能不能再通俗点描述?
作者回复: 比如你用 list.New 函数创建了一个 List 类型的双向链表,然后通过它的一些方法往里面塞了一些元素。可以往里面塞的元素的方法有 PushFront、PushBack、InsertAfter、InsertBefore 等。 但是你发现没有,这些方法接受的新元素的类型都是 interface{} 的。也就是说,这个 List 类型的链表只接受 interface{} 类型的新元素值。 而当新元素值进入链表之后,链表会把它们再包装成 list.Element 类型的值。你看,那些往里塞元素值的方法返回的都是被包装后的 *list.Element 类型的元素值。 当你像我这样浏览了 container/list.List 类型的相关 API 之后,就应该可以明白我问这个问题的背景了。 这个 List 类型只会接受 interface{} 类型的新元素值,并且只会吐出 *list.Element 类型的已有元素值。显然,任何移动已有元素值或者删除已有元素值的方法,都只会接受该链表自己吐出来的“Element 值”。因此,对于我们自己生成的“Element 值”,这个链表的任何方法都是不会接受的。 当然了,如果你之前完全没用过 List 类型,可能会觉得这个问题有些突兀。但是当你看完下面的详细解释之后,我相信你就会有所了解了。 我们这个专栏的一个风格就是:“先抛出问题,然后再解释前因后果”。目的就是,逼迫大家在碰到问题之后自己先去了解背景并试着找找答案,然后再回来看我的答案。这样的话,你对这些知识点的记忆会更牢固,不容易忘。 我非常希望这个专栏能成为大家的“枕边书”,而不是听听音频就放在一边的那种。所以才有了这样的结构设计。如果你们能在今后碰到问题时想起这个专栏,到这里翻一翻并能找到答案的线索,那我就太高兴了。
2019-04-23541 - fliter为什么不把list像slice,map一样作为一种不需要import其他包就能使用的数据类型?是因为使用场景较后两者比较少吗
作者回复: 这需要一个过程,之前list也不是标准库中的一员。况且也没必要把太多的东西多做到语言里,这样反倒不利于后面的扩展。
2018-08-29210 - Zer0不能把自己生成的Element传给List主要是因为Element的list成员是不开放的,我们不能操作,而在List上操作Element的时候是会判断Element的list成员是否是自己。是这样吗?
作者回复: ✅
2019-08-066 - Geek_a8be59您好 能否出一个list 链表生成的一个图解,现在我看源码用图去模拟生成 一直搞混掉,特别是在初始化的时候prev和next都指向自身的root 这个很迷糊 比如: c.PushBack("123") c.PushFront("456") c.PushFront("789") 根据个人图解应该是789-》456-》nil,为什么能遍历出来很不清楚。能否有一个从初始化到最后生成的样例看一下 万分感谢
作者回复: 按照你这三行代码,应该是 789 -> 456 -> 123 啊,你那个“789-》456-》ni”是怎么出来的? 这个链表里所谓的 root 就是用来表示链表两端的尽头的。所以,这个链表的末端实际上并不是 nil ,而是 root。只是在 Element 的 Next 方法中,如果发现它的 next 字段的值等于 root,就会返回 nil 而已。 明白了吗?
2019-06-2626 - 李斌用 vscode 就蛮好的,我之前是八年 vim 党,写 golang 时硬生生地被掰成 vscode
作者回复: 嗯,也算是与时俱进吧,未来有脑机接口了,也就用不着这些了。
2018-10-3035 - 雷朝建老师, 我看了一下list.go的源码,发现一个疑问是:延迟初始化的含义就是调用lazyInit,它的一个判断条件是:l.root.next==nil; 但是我们在使用list时候,不是先调用New函数吗?那么不应该会出现l.root.next为nil的情况的。 什么时候回出现l.root.next==nil, 从而导致源码中每次的PushFront等操作调用lazyInit呢?
作者回复: List 是一个 struct 啊,有了 lazyInit 你就可以直接 var myList list.List 了啊。这不是就做到开箱即用了吗?
2021-04-023 - 杨震以后再有课的话 希望老师多加点图 虽然费点事 但应该更多为学员着想吧。文字阐述一点也不直观。
作者回复: OK。
2020-08-253 - jackstraw我尝试打印了 “var l = list.New()” 与 “var l list.List”两种方式的l类型,发现是不一样的,但是下面的操作却都是可以的 func main() { //l := list.New() var l list.List e4 := l.PushBack(4) e1 := l.PushFront(1) l.InsertBefore(3, e4) l.InsertAfter(2, e1) //travel(l) travel(&l) }
作者回复: 当然不一样,list.New 返回的是指针值。另外你可以再看看讲结构体和方法那篇文章。
2019-07-093 - Sky这一讲没有实例代码
作者回复: 建议大家在阅读这一篇文章时对照着 container 包的文档看。对这几个类型的 API 有一定了解之后,使用就是水到渠成的事情了。 自己先试一试,如果有具体的问题,可以来这里问。
2019-06-122 - 白有才这课程就像小说里的武功秘籍, 看了你不一定会练, 所以练成绝世武功的人就少之又少
作者回复: 人生的终极意义不就是练成绝世武功嘛!;-)
2021-08-12