一、概念介绍

下面这副图是我们单链表运煤车队。

每节运煤车就是单链表里的元素,每节车厢里的煤炭就是元素中保存的数据。前后车通过锁链相连,作为单链表运煤车,从1号车厢开始,每节车厢都知道后面拉着哪一节车厢,却不知道前面是哪节车厢拉的自己。第一节车厢没有任何车厢拉它,我们就叫它车头,第五节车厢后面拉其他车厢,我们称为车尾。

作为单链表它最大的特点就是能随意增加车队的长度,也能随意减少车队的长度。这是比数组公交车最大的优点。

二、Go语言实现讲解

1、节点

每节车厢都由车体、绳索和煤炭构成。在Go语言中表示这种自定义组合体的类型就是结构,当然为了通用性,我们这里要把车厢转换成节点也就是元素,煤炭转换成数据,绳索转换成指针。

    type Node struct {data Objectnext *Node}

用张图来描述这种对应关系。

这里结构体Node表示车厢,data表示煤炭用Object类型,next是牵着下节车厢的绳索,用指针表示。

对于车厢来说,除了放煤炭外,还能放瓜果、衣物、饭菜等等,所以这里data的类型必须通用,当然Go里是没有Java里的Object类型的,所以我们就自己定义了一个。

    type Object interface{}

2、链表

光有车厢还不够,我们还要描述车厢组成的车队。每个单链表车队都有车头、车尾和车厢数量,我们同样以结构来表现。

    type List struct {size uint64 // 车辆数量head *Node  // 车头tail *Node  // 车尾}

3、方法

(1)初始化

第一步就是组装单链表车队,这就是初始化。不过开始的时候车队是个空壳,一个车厢没有。

    func (list *List) Init() {(*list).size = 0    // 此时链表是空的(*list).head = nil  // 没有车头(*list).tail = nil  // 没有车尾}

(2)添加元素

当前的单链表是空的,所以我们要向里面添加元素。

    func (list *List) Append(node *Node) {(*list).head = node // 这是单链表的第一个元素,也是链表的头部(*list).tail = node // 同时是单链表的尾部(*list).size = 1    // 单链表有了第一个元素}

现在单链表有了第一个元素,我还想再添加一个元素,当然是添加到单链表尾部。

    func (list *List) Append(node *Node) {if (*list).size == 0 { // 无元素的时候添加(*list).head = node // 这是单链表的第一个元素,也是链表的头部 (*list).tail = node // 同时是单链表的尾部(*list).size = 1    // 单链表有了第一个元素} else { // 有元素了再添加oldTail := (*list).tail(*oldTail).next = node  // node放到尾部元素后面(*list).tail = node     // node成为新的尾部(*list).size++          // 元素数量增加}}

分析上面的代码存在3处疑点,元芳你怎么看?属下认为
第一,node如果为空,则添加无任何意义;
第二,代码中存在重复的地方;
这第三么,卑职如何才能知道新增结果?
下面大卫哥顺着元芳的思路改进下代码。

    func (list *List) Append(node *Node) bool {if node == nil {return false}(*node).next = nil// 将新元素放入单链表中if (*list).size == 0 { (*list).head = node  } else { oldTail := (*list).tail(*oldTail).next = node  }// 调整尾部位置,及链表元素数量(*list).tail = node // node成为新的尾部  (*list).size++      // 元素数量增加return true}

(3)插入元素

一天领导让大卫哥把他小舅子安排到第一个,于是大卫哥为了拍好领导马屁。绞尽脑汁弄了一个方法。

   func (list *List) Insert(node *Node) bool {if node == nil {return false}(*node).next = (*list).head   // 领导小舅子排到之前第一名前面(*list).head = node           // 领导小舅子成为第一名(*list).size++return true}

来托关系插队的人越来越多,领导的关系户不能动,只能插后面人的队了。于是大卫哥又修改了代码,增加了位置参数。

    func (list *List) Insert(i uint,node *Node) bool {// 空的节点、索引超出范围和空链表都无法做插入操作if node == nil || i > (*list).size || (*list).size == 0 {return false}if i == 0 { // 直接排第一,也就领导小舅子才可以(*node).next = (*list).head(*list).head = node} else {// 找到前一个元素preItem := (*list).headfor j := 1 ; j < i; j++ { // 数前面i个元素preItem = (*preItem).next}// 原来元素放到新元素后面,新元素放到前一个元素后面(*node).next = (*preItem).next(*preItem).next = preItem}(*list).size++ return true}

(4)删除元素

插队的关系户太多,影响了正常排队的人,被人投诉,大卫哥只好想办法删除一些。

    func (list *List) Remove(i uint, node *Node) bool {if i >= (*list).size {return false}if i == 0 { // 删除头部node = (*list).head(*list).head = (*node).nextif (*list).size == 1 { // 如果只有一个元素,那尾部也要调整(*list).tail = nil}} else {preItem := (*list).headfor j := 1; j < i; j++ {preItem = (*preItem).next}node = (*preItem).next(*preItem).next = (*node).nextif i == ((*list).size - 1) { // 若删除的尾部,尾部指针需要调整(*list).tail = preItem}}(*list).size--return true}

(5)获取

为了获取某个位置的元素,我们需要一个方法。

    func (list *List) Get(i uint) *Node {if i >= (*list).size {return nil}item := (*list).headfor j := 0; j < i ; j++ {    // 从head数i个item = (*item).next}return item}

到这里基本框架已经出来了,不过还有几个接口还没实现,作为课后作业。

三、小结

单链表就和列车类似,一个接着一个,所以本节从列车类比介绍了单链表的Go语言实现。在接口实现部分大卫哥以序号作为链表中每个节点的操作关键字。在实际应用中,我们往往以data中的某一个字段作为操作关键字。所以这也衍生出链表的不同接口,大家可以参考大卫哥留的链接中的代码实现作为理解。同时有些实现将表头独立出来并不存放数据,这在一定程度上简化了代码的实现。

代码下载

四、习题

(1)补全GetSize,RemoveAll,GetHead和GetTail的定义和实现。
(2)以data作为参数,考虑单链表的实现。
(3)将单链表的head独立出来,此时的head是独立的,不存放data,如下图,考虑单链表的实现,并比较这种实现。

(4)如果将head和tail都独立出来,都不存放data,此时的单链表如何实现?这样实现的代码在插入删除操作时候是不是更容易点?

转载于:https://www.cnblogs.com/lanrenji/p/9691195.html

第一节 如何用Go实现单链表相关推荐

  1. [XJTUSE]数据结构学习——第一章 线性表 1.3 单链表的实现(JAVA)

    文章目录 1.3 单链表的实现(JAVA) 1.curr指针与头结点的说明 2.插入和删除操作的说明 插入 删除 1.3 单链表的实现(JAVA) 链表是由一系列叫做表的结点(node)的对象组成的, ...

  2. 如何用java写单链表_如何使用Java实现单链表?

    首先构建节点类: package com.fzw.sf; public class Node { private Object data; private Node next; Node(Object ...

  3. threejs入门第一节如何用threejs创建一个简单的场景

    什么是threejs? threejs是一个用于在浏览器中绘制3D图像的JS库.它是基于webgl实现了,包括了webgl1和webgl2的渲染引擎.同时也包括了最新的webgpu.(部分浏览器基本不 ...

  4. Java单链表反转 详细过程

    Java单链表反转 Java实现单链表翻转     [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article/details/51119499 (一) ...

  5. 通用版!完整代码,单链表SingleLinkedList增删改查,反转,逆序,有效数据等Java实现

    文章目录 节点类 链表类(主要) 测试类 小结 节点类 可以根据需要,对节点属性进行修改.注意重写toString()方法,以便后续的输出操作. //节点类 class Node {public in ...

  6. 用c++实现简单单链表,双链表,二叉树类

    在刷题时,如何用c++写单链表 双链表和 二叉树类呢? 单链表: class ListNode {public: int value; ListNode *next; ListNode() : val ...

  7. 单链表删除所有值为x的元素_双链表的基本实现与讲解(C++描述)

    双链表 双链表的意义 单链表相对于顺序表,确实在某些场景下解决了一些重要的问题,例如在需要插入或者删除大量元素的时候,它并不需要像顺序表一样移动很多元素,只需要修改指针的指向就可以了,其时间复杂度为 ...

  8. 结构体类型数据单链表的操作

    第1关:头插法创建学生数据类型单链表 任务描述 本关任务:给定一个含有n个学生数据元素的数组a,用头插法来快速创建整个单链表. 测试说明 平台会对你编写的代码进行测试. 测试输入: 5 10010 L ...

  9. 单链表的创建--从零开始

    2021.2.14更新 结合很多小伙伴的困惑,博主录制了一个视频讲解,如果大家感兴趣,欢迎跳转到我的b站视频<单链表的创建-从零开始>(P.S.这是我录制的第一个视频,因为是在晚上,怕打扰 ...

最新文章

  1. 有声专栏-宏基因组专业词汇讲解
  2. 红茶一杯话Binder(传输机制篇_上)
  3. 眨眼检测 疲劳检测,分享代码
  4. inline-block代替浮动布局float:left列表布局最佳方案
  5. 在C#后代码里使用IE WEB Control TreeView
  6. 求数组中最长连续递增子序列
  7. pku 2976 Dropping tests 01分数规划
  8. Spring Cloud学习笔记---Spring Cloud Sleuth--新建两个互相调用的服务测试zipkin
  9. PMP考试扫盲:超详细的PMP考试小白攻略,必看篇
  10. [.NET] ConfuserEx脱壳工具打包
  11. Python练习册,每天一个小程序(二)
  12. 健康知识竞答线上活动方案——微信答题小程序实现
  13. C语言课程设计——停车场管理系统
  14. 天图投资冲刺港股:资产管理规模249亿 投了小红书与奈雪
  15. 计算机网络之应用层Tips
  16. 2.1 Converting Celsius to Fahrenheit
  17. dedeCMS采集规则各大CMS采集规则通用
  18. 成都盛铭轩:客服应该怎么做
  19. 机械加工工艺规程的制订
  20. 关于 js 数组遍历的几种方式

热门文章

  1. EIGRP MD5认证实例
  2. php接收vb post数据,VB Post方式提取网页数据
  3. linux常用压缩/解压命令
  4. maven安装以及常用配置,idea如何配置maven
  5. php生成迷宫图片,PHP实现基于回溯法求解迷宫问题的方法详解
  6. EMF-edit功能解析
  7. 装机防骗武器——鲁大师
  8. 34步优化sql语句
  9. 放大器的传递函数_这么酷,采用极致小巧的运算放大器设计麦克风电路!
  10. 安装Docker环境并下载TensorFlow镜像