Go基础2:数据结构(一)
这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记。
1.数组
数组是一段固定长度的连续内存区域。
在Go语言中,数组从声明时就确定,使用时可以修改数组成员,但是数组大小不可变化。
1.1 声明数组
var team [3]string
team[0] = "hammer"
team[1] = "soldier"
team[2] = "mum"
1. 2 初始化数组
var team = [3]string{"hammer", "soldier", "mum"}
var team = [...]string{"hammer", "soldier", "mum"}
arr := [3]int{1, 2, 3}
...
表示让编译器确定数组大小。上面例子中,编译器会自动为这个数组设置元素个数为3。
1.3 遍历数组
for k, v := range team {
fmt.Println(k, v)
}
/*
0 hammer
1 soldier
2 mum
*/
1.4 读取文本文件
data.txt
70.5
90.3
88.2
func main() {
// 读取文件
file, err := os.Open("../data.txt")
if err != nil {
log.Fatal(err)
}
// 为文件创建一个扫描器,返回一个从文件中读取的bufio.Scanner值。
scanner := bufio.NewScanner(file)
// 循环读取行, 一旦到达文件的末尾(或出现错误),Scan将返回false,循环将退出。
for scanner.Scan() {
fmt.Println(scanner.Text())
}
err = file.Close()
if err != nil {
log.Fatal(err)
}
// 如果扫描文件时出现错误,报告并退出程序
if scanner.Err() != nil {
log.Fatal(scanner.Err())
}
}
读取文本文件到数组
var numbers [3]float64
file, err := os.Open(filename)
i := 0
scanner := bufio.NewScanner(file)
for scanner.Scan() {
numbers[i], err = strconv.ParseFloat(scanner.Text(), 64)
i++
}
2. 切片(slice)
动态分配大小的连续空间
Go语言切片的内部结构包含地址、大小和容量。切片一般用于快速地操作一块数据集合。
2.0 声明切片
区别于数组,声明切片变量并不会自动创建一个切片,可以调用make函数,传递切片类型及长度:
var notes []string
notes = make([]string, 3)
2.1 从数组或切片生成新的切片
切片默认指向一段连续内存区域,可以是数组,也可以是切片本身。
var a = [3]int{1, 2, 3}
fmt.Println(a, a[1:2])
切片有点像C语言里的指针。指针可以做运算,但代价是内存操作越界。切片在指针的基础上增加了大小,约束了切片对应的内存区域,切片使用中无法对切片内部的地址和大小进行手动调整,因此切片比指针更安全、强大。
表示原有的切片
a[:]
重置切片,清空拥有的元素
a[0:0]
切片是动态结构,只能与nil判定相等,不能互相判等时。
2.2 使用make()函数构造切片
如果需要动态地创建一个切片,可以使用make()内建函数,格式如下:
make([]T, size, cap)
- T:切片的元素类型。
- size:就是为这个类型分配多少个元素。
- cap:预分配的元素数量,这个值设定后不影响size,只是能提前分配空间,降低多次分配空间造成的性能问题。
make创造的切片后,后续运用该切片创造的新切片类似于指针只是指向旧切片,不创造新空间。
2.3 使用append()函数为切片添加元素
内建函数append()
可以为切片动态添加元素。
每个切片会指向一片内存空间,这片空间能容纳一定数量的元素。当空间不能容纳足够多的元素时,切片就会进行“扩容”。“扩容”操作往往发生在append()
函数调用时。
切片扩容规则:
如果切片的容量小于1024个元素,那么扩容的时候slice的cap就乘以2;一旦元素个数超过1024个元素,增长因子就变成1.25。
如果扩容之后,还没有触及原数组的容量,那么,切片中的指针指向的位置,就还是原数组,如果扩容之后,超过了原数组的容量,那么,Go就会开辟一块新的内存,把原来的值拷贝过来,这种情况丝毫不会影响到原数组。
var car []string
// 添加1个元素
car = append(car, "Old Driver")
// 添加多个元素
car = append(car, "Ice", "Sniper", "Monk")
// 添加切片
team := []string{"Pig", "Flyingcake", "Chicken"}
car = append(car, team...)
fmt.Println(car)
通常情况append只是用来往切片中加一个一个的元素,如果要往切片中加另一个切片,需要使用 …
2.4 复制切片元素到另一个切片
copy(destSlice, srcSlice []T) int
- src Slice为数据来源切片。
- dest Slice为复制的目标。
目标切片必须分配过空间且足够承载复制的元素个数。来源和目标的类型一致,copy的返回值表示实际发生复制的元素个数。
2.5 从切片中删除元素
Go语言并没有对删除切片元素提供专用的语法或者接口,需要使用切片本身的特性来删除元素
seq := []string{"a", "b", "c", "d", "e"}
// 指定删除位置
index := 2
// 查看删除位置之前的元素和之后的元素
fmt.Println(seq[:index], seq[index+1:])
// 将删除点前后的元素连接起来
seq = append(seq[:index], seq[index+1:]...)
fmt.Println(seq)
3. map
Go语言提供的映射关系容器为map。map使用散列表(hash)实现。
散列表可以简单描述为一个数组(俗称“桶”),数组的每个元素是一个列表。
根据散列函数获得每个元素的特征值,将特征值作为映射的键。
如果特征值重复,表示元素发生碰撞。碰撞的元素将被放在同一个特征值的列表中进行保存。
散列表查找复杂度为O(1),和数组一致。最坏的情况为O(n),n为元素总数。
散列需要尽量避免元素碰撞以提高查找效率,这样就需要对“桶”进行扩容,每次扩容,元素需要重新放入桶中,较为耗时。
平衡树类似于有父子关系的一棵数据树,每个元素在放入树时,都要与一些节点进行比较。平衡树的查找复杂度始终为O(log n)
声明一个映射
var map[KeyType]ValueType
// 声明一个映射,并创建它
scene := make(map[string]int)
scene["route"] = 66
fmt.Println(scene["route"])
v := scene["route2"]
需要明确知道查询中某个键是否在map中存在
v, ok := scene["route"] // 66 true
使用delete()内建函数从map中删除一组键值对
delete(map, 键)
清空map的唯一办法就是重新make一个新的map。不用担心垃圾回收的效率,Go语言中的并行垃圾回收效率比写一个清空函数高效多了。
本文来自博客园,作者:micromatrix,转载请注明原文链接:https://www.cnblogs.com/cenjw/p/golang-note-basic-data-structural.html
posted on 2022-05-14 15:48 micromatrix 阅读(45) 评论(0) 编辑 收藏 举报