Go语言数据结构与算法-基础数据结构

因为要计划刷LeetCode了,虽然之前用C++刷过,但是我发现我学完go语言了,对里面的数据结构并没有很熟悉。遇到想要用的数据结构不知道怎么用,所以我在这里介绍一下Go语言中基础的数据结构怎么写。

数组/切片

最最基础的内容,可以使用var slice []int显示声明切片,注意此时显示声明的切片slice是nil值,而slice := []int{}中slice不为nil,即使切片为空。注意如果向参数传递切片,会改变切片,而传递数组则不会改变数组。

Go 复制代码
var arr [5]int //定长数组

slice := []int{1,2,3}  //动态切片
slice := append(slice,4) //扩容

链表

需要定义链表的结构,注意哈,这里的指针零值也是nil,和上面的切片的零值是一样的。我们可以定义双向链表,就是多加一个Pre指针,还有其他结构的链表,只需要修改数据结构即可。

Go 复制代码
type ListNode struct{
  Var int
  Next *ListNode   //指针零值是nil
}

head := &ListNode{Var: 0}
head.Next := &ListNode{Var: 1}   

type ListNodeNew struct{
  Var int
  Next *ListNodeNew
  Pre *ListNodeNew
}

二叉树

除了普通二叉树之外,我们还可能用到多叉树,只需要定义指针数组即可。go语言中比较省事的就是不需要担心堆栈的问题,如果是C++,还需要从堆中申请内存。

Go 复制代码
type TreeNode{
  Var int
  Left *TreeNode
  Right *TreeNode
}

head := &TreeNode{Var: 0}
head.Left := &TreeNode{Var: 1}
head.Right := &TreeNode{Var: 2}

type NNode{
  Var int
  Children []*NNode
}

栈/队列

以下都是基于切片实现的,不过还有双端队列,或者循环队列的数据结构,这里就不给出例子了,请读者自行实现。

Go 复制代码
//基于切片实现
stack := []int{}  //空切片
stack := append(stack,6)  //定义入栈
v := stack[len(stack)-1]   //取栈顶内容
stack := stack[:len(stack)-1]  //定义出栈

queue := []int{}
queue := append(queue,6)  //入队
v := queue[0]  //取队首内容
queue := queue[1:]  //出队

这个重点不在于数据结构本身,而是堆的操作函数,可以使用type heap []int来定义堆(切片)。但是重点在于实现堆的方法。首先有大根堆还有小根堆,还有上浮下沉,交换等方法,大小根堆的实现还不一样。

哈希表

也就是map,在go语言中有该数据结构。通过map[key]value来定义,注意使用make的时候会进行初始化,也就是m不为nil,但是是一个空的哈希表,也可以使用m := map[string]int{}来初始化。

Go 复制代码
m := make(map[string]int) //定义哈希表的键值对的数据类型
m["key"] = 42    //添加键值对
value, exists := m["key"]   //安全的取值
delete(m, "key")   //删除键值对

集合

集合可以说是没有值的键值对,可以利用set := make(map[string]bool)来模拟集合,也就是bool来占位,但是没有什么作用。更好的方法是用空结构体struct{}作为value,减少内存占用,因为空结构体不分配内存。

Go 复制代码
set := make(map[string]struct{})
// 添加元素
set["apple"] = struct{}{}
set["banana"] = struct{}{}

// 检查元素是否存在
if _, exists := set["apple"]; exists {
    fmt.Println("apple exists")
}

// 删除元素
delete(set, "banana")

好像还有图没有实现,可以用邻接矩阵,或者邻接表的方式实现,还有并查集、跳表、布隆过滤器这些数据结构。不过这几部分内容比较多,而且也比较难,只能放到后面再讲了。