go语言:数组(Array)、链表(Linked List)、栈(Stack)、队列(Queue) 、树(Tree)、散列表(Hashing)

申明:本文只用做自己学习记录

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值