IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> Go的数组和切片 -> 正文阅读

[数据结构与算法]Go的数组和切片

相同和差异

数组和切片都是集合类型,都是可以用来存储某一类数据结构
但是数组的长度是固定的,切片的长度是可变的。
切片属于引用数据类型, 数组属于值类型。

关系探讨

切片可以看作是对数组的又一次封装,在切片的底层数据结构还是数组,切片就可以看作是是对数组内某个连续片段的引用。
lencap函数对数组和切片的结果也不同。
在数组中, 数组的长度len等于数组的容量cap
切片的长度则表示对底层数组的引用的连续片段的长度,容量则是底层数组的容量。
看一下通过通过make声明数组的结果

func main() {
	slice1 := make([]int, 4)
	slice2 := make([]int, 4, 8)
	fmt.Println("array len is", len(slice1))
	fmt.Println("array cap is", cap(slice1))
	fmt.Println("slice len is", len(slice2))
	fmt.Println("slice cap is", cap(slice2))
}

以上案例输出为:

slice1 len is 4
slice1 cap is 4
slice2 len is 4
slice2 cap is 8

结果说明如果在声明切片的时候不指定容量, 那么切片的容量就等于切片的长度。
同时使用make切片的引用是从底层数组的index为0元素开始的。 现在slice2 和底层数组的关系如下图

在这里插入图片描述
那么我们append一下slice2 , 代码

func main() {
	slice1 := make([]int, 4)
	slice2 := make([]int, 4, 8)
	fmt.Println("slice1 len is", len(slice1))
	fmt.Println("slice1 cap is", cap(slice1))
	fmt.Println("slice2 len is", len(slice2))
	fmt.Println("slice2 cap is", cap(slice2))
	slice3 := append(slice2, 1)
	fmt.Println("slice3 len is", len(slice3))
	fmt.Println("slice3 cap is", cap(slice3))
}

结果:

slice1 len is 4
slice1 cap is 4
slice2 len is 4
slice2 cap is 8
slice3 len is 5
slice3 cap is 8

可以看到slice3 的len 是5,但是cap依然是8。 说明底层数组并没有发生变化。
如果append导致len超过8呢

func main() {
	slice1 := make([]int, 4)
	slice2 := make([]int, 4, 8)
	fmt.Println("slice1 len is", len(slice1))
	fmt.Println("slice1 cap is", cap(slice1))
	fmt.Println("slice2 len is", len(slice2))
	fmt.Println("slice2 cap is", cap(slice2))
	for i := 0; i < 5; i++ {
		slice2 = append(slice2, 1)
	}
	fmt.Println("slice2 append len is", len(slice2))
	fmt.Println("slice2 append cap is", cap(slice2))
}

结果:

slice1 len is 4
slice1 cap is 4
slice2 len is 4
slice2 cap is 8
slice2 append len is 9
slice2 append cap is 16

发现底层数组的容量翻倍了,由于数组的容量和长度不可变,是切片又申请了一个新的底层数组来使用。

切片的切割

如果在原有的切片上截取新的切片, 那么新的切片使用的还是原来切片的数组吗?
看如下代码:

func main() {
	sliceAll := []int{1, 2, 3, 4, 5, 6, 7, 8}
	slice := sliceAll[2:6]
	fmt.Println("slice len is", len(slice))
	fmt.Println("slice cap is", cap(slice))
	sliceAll[2] = 88
	fmt.Println("slice cap is", slice[0])
}

结果:

slice len is 4
slice cap is 6
slice cap is 88

新的切片的容量不是8, 同时我们改变了原有切片的一个数字, 新的切片也改变了,说明两个切片依然是引用的同一个底层数组。

因为切片是无法向左拓展的,左边的数据没用,所以新的切片引用不是从index为0开始的,是从index为2开始的,如下图红框内部所示, 那么这个时候容量就是6了。说明切片的容量并不是一直等于底层数组的容量,而是引用起始的index到数组末尾的容量。
在这里插入图片描述
如果这个时候切片元素满了会怎么办,是基于切片的容量还是底层数组的容量来扩容呢?代码如下:

func main() {
	sliceAll := []int{1, 2, 3, 4, 5, 6, 7, 8}
	slice := sliceAll[2:6]
	fmt.Println("slice len is", len(slice))
	fmt.Println("slice cap is", cap(slice))
	sliceAll[2] = 88
	fmt.Println("slice cap is", slice[0])
	for i := 0; i < 3; i++ {
		slice = append(slice, 99)
	}
	fmt.Println("slice cap is", cap(slice))
	fmt.Println("sliceAll cap is", cap(sliceAll))
}

结果:

slice len is 4
slice cap is 6
slice cap is 88
slice cap is 12
sliceAll cap is 8

发现是基于6翻倍的,说明切面扩容不是基于底层数组的容量, 而是基于切片的容量,还有在申请新的数组的同时并没有改变原来切片sliceAll 的引用的数组,原有切片的容量还是8。

总结

切片是基于数组的一次封装, 解决了数组长度不可变的问题,但是其底层存储的实现依然是基于数组操作,尤其是容量不足的时候,会再次申请新的数组作为存储使用。 所以再切片的使用过程中如果可以提前确定容量,最好是声明容量创建,因为每次扩容,新的空间的申请和数据复制时比较消耗性能的。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-05-09 12:59:06  更:2022-05-09 13:01:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 3:23:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码