申明:本文只用做自己学习记录
0 简介
- 线性数据结构:数组(Array)、链表(Linked List)、栈(Stack)、队列(Queue)
- 非线性数据结构:树(Tree)、图(Heap)、散列表(Hashing)、堆(Graph)
1 数组(Array)
1.1 定义
- 数组是将相同类型的元素存储于连续内存空间的数据结构。根据数组长度可不可变,可分为静态数组和动态数组
1.2 数组的基本操作
- Insert——在指定索引位置插入一个元素
Get——返回指定索引位置的元素
Delete——删除指定索引位置的元素
Size——得到数组所有元素的数量
1.3 代码
1.3.1 静态数组
//定义
//方式1:
var a [10] int //表示的范围是 a[0],a[1],a[2].......,a[9];需要指明数组的容量
//方式2:
a := [10]int{}
//注:在go语言静态数组中,其元素不可以增、删;可以改、查
1.3.2 动态数组
//定义
//方式1:
var a []int //声明切片和声明数组一样,只是少了长度,此为空(nil)切片
//方式2:
a := []int{1, 2, 3}
//方式3:
a := make([]int, 5, 10) //其中5为切片长度,10为计算机为该切片分配的空间
//由于元素类型为int,没有赋值时,切片内部元素都为0
//增
a[6] := 8 //增加第六个元素,并赋值为8,int类型
//删
a := a[:len(a)-1] //删除最后一个元素,其实就是重新赋值
//改
a[2] := 6 //将第3个元素为(默认为0)改为6,int类型
//查
x := a[3] //查询切片a的第四个元素,并赋值给x
2 链表(Linked List)
2.1 定义
- 链表以节点为单位,每个元素都是一个独立对象,在内存空间的存储是非连续的。链表的节点(Node)对象具有两个成员变量:值 (Data) 和 后继节点引用(Next)。
- 单链表
头指针:没有数据,只有地址,专门存放头结点的地址
尾结点:有数据,也有地址,地址值始终为nil - 循环链表
循环链表跟单链表唯一的区别就在尾结点。单向链表的尾结点指针指向空地址,表示这就是最后的结点了,而循环链表的尾结点指针是指向链表的头结点 - 双向链表
双向链表的每个数据结点中都有两个指针,分别指向直接后继和直接前驱从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
2.2 链表的基本操作:
- InsertAtEnd——在链表的末尾插入指定元素
InsertAtHead——在链接列表的开头/头部插入指定元素
Delete——从链接列表中删除指定元素
DeleteAtHead——删除链接列表的第一个元素
Search——从链表中返回指定元素
isEmpty——如果链表为空,则返回true
2.3 代码
//单链表节点
type SingleNode struct {
Data interface{} // 节点数据
Next *SingleNode // 指针指向下一个节点的地址
}
//双链表节点
type DoubleNode struct {
Data interface{} //节点数据
Prev *DoubleNode //前一个节点地址
Next *DoubleNode //后一个节点地址
}
3 栈(Stack)
3.1 定义
- 栈是一种具有先入后出的特点的抽象数据结构
3.2 栈的基本操作
- Push——在顶部插入一个元素
Pop——返回并移除栈顶元素
isEmpty——如果栈为空,则返回true
Top——返回顶部元素,但并不移除它
3.3 代码:
//定义栈,不确定变量类型和结构,使用了interface
type Stack struct {
//创建切片模拟栈
data []interface{}
}
//进栈操作
func (s *Stack) Push(item interface{}) interface{} {
//按顺序加入元素
s.data = append(s.data, item)
return s
}
//出栈操作
func (s *Stack) Pop() (interface{}, bool) {
var item interface{}
if len(s.data) == 0 {
return item, false
} else if len(s.data) == 1 {
//取出该元素
item = s.data[0]
//将该元素赋值为空,即删除
s.data = []interface{}{}
return item, true
} else {
//取出最后一位元素
item = s.data[len(s.data)-1]
//更新栈,删除最后一位元素
s.data = s.data[:len(s.data)-1]
//输出最后一位元素
return item, true
}
}
//查询栈中的元素
func (s *Stack) ElementAt(index int) (interface{}, bool) {
length := len(s.data)
if index >= length {
return []interface{}, false
}
return s.data[index], true
}
4. 队列(Queue)
- 队列和栈相反,是一种具有先入先出特点的抽象数据结构
4.1 队列的基本操作
- Enqueue()——在队列尾部插入元素
Dequeue()——移除队列头部的元素
isEmpty()——如果队列为空,则返回
trueTop()——返回队列的第一个元素
// 定义对列,不确定变量类型和结构,使用了interface
type Queue struct {
//定义切片模拟对列
data []interface{}
}
//定义入队
func (s *Queue) Enqueue(t []interface{}) ([]interface{}, bool) {
s.data = append(s.data, t)
return s.data, true
}
// 定义出队
func (s *Queue) Dequeue() ([]interface{}, interface{}, bool) {
if len(s.data) == 0 {
fmt.Println("该列队为空!")
return nil, nil, false
}
//取出元素
item := s.data[0] // 先进先出
//更新队列,删除取出的元素
s.data = s.data[1:len(s.data)]
return s.data, item, true
}
5. 树(Tree)
- 树是一种非线性数据结构,根据子节点数量可分为 二叉树 和多叉树,最顶层的节点称为根节点 root
- 以二叉树为例,每个节点包含三个成员变量:值 val、左子节点 left、右子节点 right
5.1代码
//定义二叉树节点
type Node struct {
Value int
Left, Right *Node
}
//创建二叉树节点
func CreateNode(v int) *Node {
return &Node{Value: v}
}
//打印二叉树节点值
func (node *Node) Print() {
fmt.Print(node.Value, " ")
}
//设置二叉树节点值
func (node *Node) SetValue(v int) {
if node == nil {
fmt.Println("setting value to nil.node ignored.")
return
}
node.Value = v
}
//前序遍历
func (node *Node) PreOrder() {
if node == nil {
return
}
node.Print()
node.Left.PreOrder()
node.Right.PreOrder()
}
//中序遍历
func (node *Node) MiddleOrder() {
if node == nil {
return
}
node.Left.MiddleOrder()
node.Print()
node.Right.MiddleOrder()
}
//后序遍历
func (node *Node) PostOrder() {
if node == nil {
return
}
node.Left.PostOrder()
node.Right.PostOrder()
node.Print()
}
//层次遍历(广度优先遍历)
func (node *Node) BreadthFirstSearch() {
if node == nil {
return
}
result := []int{}
nodes := []*Node{node}
for len(nodes) > 0 {
curNode := nodes[0]
nodes = nodes[1:]
result = append(result, curNode.Value)
if curNode.Left != nil {
nodes = append(nodes, curNode.Left)
}
if curNode.Right != nil {
nodes = append(nodes, curNode.Right)
}
}
for _, v := range result {
fmt.Print(v, " ")
}
}
//层数(递归实现)
//对任意一个子树的根节点来说,它的深度=左右子树深度的最大值+1
func (node *Node) Layers() int {
if node == nil {
return 0
}
leftLayers := node.Left.Layers()
rightLayers := node.Right.Layers()
if leftLayers > rightLayers {
return leftLayers + 1
} else {
return rightLayers + 1
}
}
6. 散列表(Hashing)
- 散列表是一种非线性数据结构,通过利用 Hash 函数将指定的键 key映射至对应的值 value,以实现高效的元素查找,在go语言中实现方式就是字典map