Go语言List的使用与数据结构的选择

2023-11-20

container包下的函数:

     heap      heap包提供了对任意类型(实现了heap.Interface接口)的堆操作.
     list      list包实现了双向链表.
     ring      ring实现了环形链表的操作.

一、List的使用

List列表是一种非连续存储的容器,由多个节点组成,节点通过一些变量记录彼此之间的关系。列表有多种实现方法,如单链表、双链表等。

列表的原理可以这样理解:假设 A、B、C 三个人都有电话号码,如果 A 把号码告诉给 B,B 把号码告诉给 C,这个过程就建立了一个单链表结构,如下图所示。
 


图:三人单向通知电话号码形成单链表结构


如果在这个基础上,再从 C 开始将自己的号码给自己知道号码的人,这样就形成了双链表结构,如下图所示。
 


图:三人相互通知电话号码形成双链表结构


那么如果需要获得所有人的号码,只需要从 A 或者 C 开始,要求他们将自己的号码发出来,然后再通知下一个人如此循环。这个过程就是列表遍历。

如果 B 换号码了,他需要通知 A 和 C,将自己的号码移除。这个过程就是列表元素的删除操作,如下图所示。
 


图:从双链表中删除一人的电话号码


在 Go 语言中,将列表使用 container/list 包来实现,内部的实现原理是双链表。列表能够高效地进行任意位置的元素插入和删除操作。

初始化列表

list 的初始化有两种方法:New 和声明。两种方法的初始化效果都是一致的。

1) 通过 container/list 包的 New 方法初始化 list

变量名 := list.New()


2) 通过声明初始化list

var 变量名 list.List


列表与切片和 map 不同的是,列表并没有具体元素类型的限制。因此,列表的元素可以是任意类型。这既带来遍历,也会引来一些问题。给一个列表放入了非期望类型的值,在取出值后,将 interface{} 转换为期望类型时将会发生宕机。

在列表中插入元素

双链表支持从队列前方或后方插入元素,分别对应的方法是 PushFront 和 PushBack。

提示

这两个方法都会返回一个 *list.Element 结构。如果在以后的使用中需要删除插入的元素,则只能通过 *list.Element 配合 Remove() 方法进行删除,这种方法可以让删除更加效率化,也是双链表特性之一。

下面代码展示如何给list添加元素:

 
  1. l := list.New()
  2.  
  3. l.PushBack("fist")
  4. l.PushFront(67)

代码说明如下:

  • 第 1 行,创建一个列表实例。
  • 第 3 行,将 fist 字符串插入到列表的尾部,此时列表是空的,插入后只有一个元素。
  • 第 4 行,将数值 67 放入列表。此时,列表中已经存在 fist 元素,67 这个元素将被放在 fist 的前面。


列表插入元素的方法如下表所示。

方  法 功  能
InsertAfter(v interface {}, mark * Element) * Element 在 mark 点之后插入元素,mark 点由其他插入函数提供
InsertBefore(v interface {}, mark * Element) *Element 在 mark 点之前插入元素,mark 点由其他插入函数提供
PushBackList(other *List) 添加 other 列表元素到尾部
PushFrontList(other *List) 添加 other 列表元素到头部

从列表中删除元素

列表的插入函数的返回值会提供一个 *list.Element 结构,这个结构记录着列表元素的值及和其他节点之间的关系等信息。从列表中删除元素时,需要用到这个结构进行快速删除。

列表操作元素:

 
  1. package main
  2.  
  3. import "container/list"
  4.  
  5. func main() {
  6. l := list.New()
  7.  
  8. // 尾部添加
  9. l.PushBack("canon")
  10.  
  11. // 头部添加
  12. l.PushFront(67)
  13.  
  14. // 尾部添加后保存元素句柄
  15. element := l.PushBack("fist")
  16.  
  17. // 在fist之后添加high
  18. l.InsertAfter("high", element)
  19.  
  20. // 在fist之前添加noon
  21. l.InsertBefore("noon", element)
  22.  
  23. // 使用
  24. l.Remove(element)
  25. }

代码说明如下:
第 6 行,创建列表实例。
第 9 行,将 canon 字符串插入到列表的尾部。
第 12 行,将 67 数值添加到列表的头部。
第 15 行,将 fist 字符串插入到列表的尾部,并将这个元素的内部结构保存到 element 变量中。
第 18 行,使用 element 变量,在 element 的位置后面插入 high 字符串。
第 21 行,使用 element 变量,在 element 的位置前面插入 noon 字符串。
第 24 行,移除 element 变量对应的元素。

下表中展示了每次操作后列表的实际元素情况。
 

列表元素操作的过程
操作内容 列表元素
l.PushBack("canon") canon
l.PushFront(67) 67, canon
element := l.PushBack("fist") 67, canon, fist
l.InsertAfter("high", element) 67, canon, fist, high
l.InsertBefore("noon", element) 67, canon, noon, fist, high
l.Remove(element) 67, canon, noon, high

遍历列表——访问列表的每一个元素

遍历双链表需要配合 Front() 函数获取头元素,遍历时只要元素不为空就可以继续进行。每一次遍历调用元素的 Next,如代码中第 9 行所示。

 
  1. l := list.New()
  2.  
  3. // 尾部添加
  4. l.PushBack("canon")
  5.  
  6. // 头部添加
  7. l.PushFront(67)
  8.  
  9. for i := l.Front(); i != nil; i = i.Next() {
  10. fmt.Println(i.Value)
  11. }

代码输出如下:
67
canon

代码说明如下:

  • 第 1 行,创建一个列表实例。
  • 第 4 行,将 canon 放入列表尾部。
  • 第 7 行,在队列头部放入 67。
  • 第 9 行,使用 for 语句进行遍历,其中 i:=l.Front() 表示初始赋值,只会在一开始执行一次;每次循环会进行一次 i!=nil 语句判断,如果返回 false,表示退出循环,反之则会执行 i=i.Next()。
  • 第 10 行,使用遍历返回的 *list.Element 的 Value 成员取得放入列表时的原值。

代码实例:

package main

import (
	"container/list"
	"fmt"
	"strconv"
)
/*
list是一个双向链表。该结构具有链表的所有功能。
*/
func main01() {
	fmt.Println("入队列")
	//初始化一个list
	list1 := list.New()//初始化list
	//依次在尾部添加
	list1.PushBack(1)
	list1.PushBack("hello")
	list1.PushBack(3.14)
	list1.PushBack("江洲")
	//在头部添加
	list1.PushFront("888")


	//读取首元素
	frist := list1.Front().Value
	//fmt.Printf("%T",m)
	fmt.Println(frist)

	//获取最后一个入队列的元素
	last := list1.Back().Value
	fmt.Println(last)

}
func main() {
	list1 := list.New()
	for i := 0; i < 10; i++ {
		str :="hello"+strconv.Itoa(i)
		list1.PushBack(str)
	}
	list1.InsertAfter("你好", list1.Front())//插入数据:链表中首元素之后
	list1.InsertBefore("jiangzhou",list1.Back())//插入数据:链表中末尾元素之钱
	//fmt.Println(list1.Len())
	fmt.Println("遍历所用的元素")
	for i:=list1.Front();i!=nil;i=i.Next(){//依据链表进行
		fmt.Print(i.Value,"\t")
	}
	/*
	依次取出元素,同时删除原有数据
	*/
	fmt.Println()
	len := list1.Len() //获取原有长度
	for i := 0; i < len; i++ {
		de := list1.Front()
		fmt.Print(de.Value,"\t")
		list1.Remove(de) //出队列的首元素,同时在队列中将其删除
	}
}

 

二、存储结构的选择

Go中数据结构的选择:链表(双向链表)可以考虑选择 list,对于复杂的结构比如:区块链结构中的钱包定义:

//定义一个秘钥对结构, KeyPair
type Wallet struct {
	PrivateKey *ecdsa.PrivateKey

	//PubKey ecdsa.PublicKey

	PubKey []byte //为了传输方便,在对端可以还原
}
type Wallets struct {
	//key : 这个私钥对对应的地址,
	//value : 这个私钥对
	WalletsMap map[string]*Wallet   //wallet为定义类型
}

已经花费的UTXO结构的定义:

spentUtxts := make(map[string][]int64) //已经花费的utxo

beego项目中 使用map[string]interface的切片实现数据存储结构的使用:

//首页展示商品数据
	goods := make([]map[string]interface{},len(goodsTypes))

 

func(this*GoodsController)ShowIndex(){
	GetUser(&this.Controller)
	o := orm.NewOrm()
	//获取类型数据
	var goodsTypes []models.GoodsType
	o.QueryTable("GoodsType").All(&goodsTypes)
	this.Data["goodsTypes"] = goodsTypes

	//获取轮播图数据
	var indexGoodsBanner []models.IndexGoodsBanner
	o.QueryTable("IndexGoodsBanner").OrderBy("Index").All(&indexGoodsBanner)
	this.Data["indexGoodsBanner"] = indexGoodsBanner

	//获取促销商品数据
	var promotionGoods []models.IndexPromotionBanner
	o.QueryTable("IndexPromotionBanner").OrderBy("Index").All(&promotionGoods)
	this.Data["promotionsGoods"] = promotionGoods

	//首页展示商品数据
	goods := make([]map[string]interface{},len(goodsTypes))

	//向切片interface中插入类型数据
	for index, value := range goodsTypes{
		//获取对应类型的首页展示商品
		temp := make(map[string]interface{})
		temp["type"] = value
		goods[index] = temp
	}
	//商品数据


	for _,value := range goods{
		var textGoods []models.IndexTypeGoodsBanner
		var imgGoods []models.IndexTypeGoodsBanner
		//获取文字商品数据
		o.QueryTable("IndexTypeGoodsBanner").RelatedSel("GoodsType","GoodsSKU").OrderBy("Index").Filter("GoodsType",value["type"]).Filter("DisplayType",0).All(&textGoods)
		//获取图片商品数据
		o.QueryTable("IndexTypeGoodsBanner").RelatedSel("GoodsType","GoodsSKU").OrderBy("Index").Filter("GoodsType",value["type"]).Filter("DisplayType",1).All(&imgGoods)

		value["textGoods"] = textGoods
		value["imgGoods"] = imgGoods
	}
	this.Data["goods"] = goods



	this.TplName = "index.html"
}

总之,数据结构的选择是一项长期经验积累与不断学习的过程,选择好的数据结构可以达到事半功倍的效果。

了解更多Go语言知识https://study.163.com/course/introduction/1210620804.htm

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Go语言List的使用与数据结构的选择 的相关文章

  • java pakage、import关键字

    package介绍 常用的包 import 案例
  • C语言结构体初始化的四种方法

    定义 struct InitMember int first double second char third float four 方法一 定义时赋值 struct InitMember test 10 3 141590 method o
  • 静态功耗具体指什么

    之前我的理解一直为静态功耗等同于关机功耗 今天专门搜索了解了下 百度百科给出的定义是指漏电流功耗 是电路状态稳定时的功耗 其数量级很小 其实这个定义很模糊 怎样的状态是电路稳定状态 我自己的理解是静态功耗为两种 一 等同于关机功耗 即器件全
  • ssh连接很慢GSS failure解决办法

    什么导致了 scp 和 ssh 的登陆提示速度下降 就我自身所遇到的情况来看 这些延迟绝大部分是 GSSAPI 的认证功能导致的 你可以用 v 选项确认你的情况 例如 下面是 ssh 的详细登陆过程 cherry cherry ssh v
  • 原生JS实现随着鼠标滚动到元素位置触发对应css3动画,简单易用

    废话不多说 直接上代码 附用法 纯博主手写 看完后 觉得好左上角请点个赞 觉得不好的请留下您的建议 谢谢 此代码改版很方便 大家可以任意发挥 注意 如果不想自己写动画的 可以引入Animate css 相信这个动画库大家都不陌生 body
  • modbus协议crc校验c语言代码,modbus协议crc校验

    数据校验是数据传输必不可少的一部分 主要目的就是防止数据传输过程中出现差错 本文主要根据原理实现它的核心代码 预置1个16位的寄存器为十六进制FFFF 全1 此寄存器为CRC寄存器 把第一个8位二进制数据 即通讯信息帧的第一个字节 与16位
  • MySQL 常用高可用方案

    这一节内容来简单聊聊 MySQL 最常用的几种高可用方案 1 主从或主主 Keepalived 主从或主主 Keepalived 算是历史比较悠久的 MySQL 高可用方案 常见架构如下 其大致原理是 在主实例的 Keepalived 中
  • AIGC之Stable Diffusion 提示词学徒库

    前言 描述 本文主要用来记录 提示词TAG 一 提示词 1 提升画面品质的提示词 masterpiece 杰作 best quality 最佳品质 ultra highers 超高分辨率 8k resolution 8k分辨率 realis
  • C++基础问题

    1 在 main 函数执行之前和之后的代码可能是什么 main 函数执行之前 初始化系统相关资源 设置栈指针 初始化 static 变量和 global 变量 未初始化的全局变量赋初值 全局对象初始化 这里会调用构造函数 这是可能会调用的代
  • 为什么越来越多的 IT 人考软考?

    近几年随着国家计算机与软件技术的发展 每年报名参加软考考试的人也越来越多 据工信部新闻发布会消息 计算机软件与通信专业技术人员职业资格考试累计报考人数超过485万 2022年报考人数129万人 01 为什么越来越多的IT人考软考证书 1 软
  • 【精品示例】超实用Python爬虫入门实例——做一个优质舔狗

    引言 最近发现了一个有意思的网站 里面充斥了大量的舔狗箴言 作为一个爬虫发烧友怎么能错过此等机会 咱们直接就是上才艺 类的编写 本次爬虫使用了多协程的方案进行 保证了爬虫的速度 在这里我们新建一个爬虫类 并在里边添加上我们需要的方法 网页的
  • IDEA打包上传到阿里云私服

    上传阿里云私服报错 ERROR Failed to execute goal org apache maven plugins maven deploy plugin 2 8 2 deploy default deploy on proje
  • 通讯录系统图形化界面(C++,Qt5.12)(Visual Studio2019,QtCreator)(初学)

    目录 无用的前言 无用的话 无需用看 前言 一 开发工具 二 功能演示以及 源码和安装包 下载 三 功能介绍以及设计思路 四 代码具体实现 项目文件结构 main cpp mainwindow ui mainwindow h mainwin
  • 2.前端笔记-CSS-字体属性

    1 字体系列 CSS使用font family属性定义文本的字体系列 body font family 思源黑体 Microsoft YaHei 建议 使用英文写字体的属性值 尽量使用系统默认自带字体 保证在任何用户的浏览器都可以显示 微软
  • react 入坑学习(十四)混合菜单新模式(ANT ProLayout)

    混合菜单新模式 样例 Ant Design Pro Blog 文档 这个明显就比非混合的好看很多 今天就来试试改一改吧 现在官网中找到ProLayout 就可以找到这个混合模式的源码样例 import React from react im
  • css实现文本超出显示省略号

    一 普通情况下 1 固定width 2 overflow hidden 3 text overflow ellipsis 显示为省略号 4 white space nowrap 不换行 二 table表格里 td 设置上面的4步 table
  • Selenium 之订制启动Chrome的选项(Options)

    使用 selenium 时 我们可能需要对 chrome 做一些特殊的设置 以完成我们期望的浏览器行为 比如阻止图片加载 阻止JavaScript执行 等动作 这些需要 selenium的 ChromeOptions 来帮助我们完成 1 什
  • 3.Open3D教程——点云数据操作

    点云数据 本教程阐述了基本的点云用法 随需要的文件链接 1 显示点云 import open3d as o3d import numpy as np print Load a ply point cloud print it and ren
  • ESDA in PySal (3):Geosilhouettes:集群拟合的地理测量

    ESDA in PySal 3 Geosilhouettes 集群拟合的地理测量 Silhouette statistics Rousseeuw 1987 是观测值与给定聚类的拟合优度的非参数度量 在聚类具有 地理 解释的情况下 例如当它们

随机推荐

  • 【Linux】进程优先级,环境变量,进程地址空间

    文章目录 1 进程优先级 基本概念 查看系统进程 PRI and NI PRI vs NI 修改进程优先级的命令 其他概念 2 环境变量 基本概念 查看环境变量方法 常见环境变量 测试PATH 环境变量相关的命令 环境变量的组织方式 通过代
  • 心理学的166个现象---之六

    101 拍球效应 拍篮球时 用的力越大 篮球就跳得越高 对学生的期望值越高 学生潜能的发挥就越充分 优秀的老师总是尽可能地信任学生 不断鼓励学生 而批评则尽可能委婉 不使矛盾激化 102 旁观者效应 1993年 四川达竹矿务局一名高考超过录
  • pytorch模型训练的若干问题

    1 Net input 调用的是什么函数 为什么直接写对象名就直接调用函数了 net是创建的vgg类的对象 vgg类继承于pytorch库中类nn Module 创建类时的括号里写上父类的名字 就是继承的意思 在pytorch库中nn Mo
  • QTableWidget 设置表头颜色

    QTableWidget 设置表头颜色 方法1 setStyleSheet QHeaderView section background color qlineargradient x1 0 y1 0 x2 0 y2 1 stop 0 00
  • android sdk自带的fragment标签使用

    项目开发中要用到 下面四个大分类 上面三个小分类的情况 大分类采用viewPage 小分类 使用了sdk自带的
  • 制造业软件体系结构与互联网的差异

    本人自毕业已经13年 虽然热爱计算机 但是由于种种原因 一直在东莞的工厂混迹 感受着互联网的大潮 也不免有几分失落 伴随这去年 今年大厂裁人 许多被逼无路的程序员开始跳槽制造业 浓浓的Java气息来了 在此不免吐槽一句 请不要把写互联网程序
  • ESP32-PICO-D4下载程序出现 rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) flash read err, 1000

    备注 是我自己记录用的 有问题可以交流 用的Visual Studio Code Arduino platformio开发 最近现在在搞物联网 发现ESP32这款芯片容易上手 而且功能强大 买的开发板用起来很顺手 于是我就自己从立创开源上找
  • 解决cannot be cast to class jakarta.servlet.Servlet问题

    我的Tomcat版本是10 0 5 这个问题的主要原因是因为 10版本的Tomcat的servlet包变化了 解决问题方法 IDEA选择这个直接完美解决 IDEA选择这个直接完美解决 IDEA选择这个直接完美解决 1下载对应的包并且导入 下
  • Prim算法解决修路问题

    普里姆算法 Prim算法 图论中的一种算法 可在加权连通图里搜索最小生成树 意即由此算法搜索到的边子集所构成的树中 不但包括了连通图里的所有顶点 英语 Vertex graph theory 且其所有边的权值之和亦为最小 普里姆算法和Kru
  • storm集成kafka简单使用示例2

    StormKafkaTopo java package stormUse stormUse import java util Properties import org apache storm Config import org apac
  • 9.2 单片机上下拉电阻

    前边似乎我们很多次提到了上拉电阻 下拉电阻 具体到底什么样的电阻算是上下拉电阻 上下拉电阻都有何作用呢 上拉电阻就是将不确定的信号通过一个电阻拉到高电平 同时此电阻也起到一个限流作用 下拉就是下拉到低电平
  • app id(wildcard ID和explicit ID)

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 最近做ios游戏的平台相关的工作 平台商要求把我们产品的bundle id加上他们的标记 比如我们的bundle id叫 com lc test 如果我上CSDN的平台 就
  • CleanMyMac X4.14.1苹果Mac电脑系统最好用的系统清理工具

    macOS 平台的知名系统清理应用 CleanMyMac 在经历了一段时间的beta测试后 全新设计的 CleanMyMac X 正式上线 与 CleanMyMac3相比 新版本的 UI 设计焕然一新 采用了完全不同的风格 除了设计上的变化
  • gdb attach 方法

    第一步 获得正在运行的进程的进程号 程序编译时要有 g参数 第二步 gdb attach 根据上一步获得进程号 现在attach上去 此处可stop暂停程序 第三步 打断点 gdb有两种打断点的方式 b 行号 如果是当前文件 则直接加上行号
  • 用wordpress编辑网站使页面中的图片全屏展示和全屏轮播展示

    在利用wordpress建立网站中 页面中的bannner图如何使其全屏展示以及如何添加轮播图 一 页面中的图片如何设置为全屏图片展示 操作步骤如下 1 打开网站的后台 点击 页面 选择所有页面 如图所示 2 选择相应的页面 点击 使用El
  • nacos简易实现负载均衡

    目录 一 什么是Nacos 二 Nacos下载和安装 1 使用Windows启动 2 验证nacos是否成功启动 三 Nacos Discovery服务注册 发现 四 简易实现负载均衡 1 注册者配置 2 注册者启动类 3 注册者业务层 4
  • 数组添加进formdata_FormData使用方法详解

    FormData的主要用途有两个 1 将form表单元素的name与value进行组合 实现表单数据的序列化 从而减少表单元素的拼接 提高工作效率 2 异步上传文件 一 创建formData对象 1 创建一个空对象 通过FormData构造
  • Linux命令_sort & 排序、去重

    目录 1 语法 1 1 常用参数 2 常见用法 2 1 按数值排序 2 2 按文件大小排序 2 3 指定某一列排序 2 4 去重后排序 2 5 生成随机数 2 6 同时查看多个文件 2 7 排序后的值写入文件 可直接修改文件 1 语法 so
  • 如何使用区块链技术保护个人隐私和数据安全

    区块链技术是一种分布式账本技术 它具有不可篡改 去中心化 透明度高等特点 区块链技术能够实现数据的可信存证 隐私保护和交易安全 并且能够通过智能合约的自动执行 因此被广泛应用于金融 电商 物流 社交网络等领域 区块链技术的核心是 分布式账本
  • Go语言List的使用与数据结构的选择

    container包下的函数 heap heap包提供了对任意类型 实现了heap Interface接口 的堆操作 list list包实现了双向链表 ring ring实现了环形链表的操作 一 List的使用 List列表是一种非连续存