【声明】

非完全原创,部分内容来自于学习其他人的理论和B站视频。如果有侵权,请联系我,可以立即删除掉。

一、稀疏矩阵

若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏矩阵;与之相反,若非0元素数目占大多数时,则称该矩阵为稠密矩阵。

在存储稀疏矩阵时,可以通过只存储矩阵的行数、列数、默认值,以及非0元素的行列信息,即可达到存储整个矩阵的目的。例如,当围棋中棋子的个数很少的时候,可以通过该方式保存棋局,下一次打开时也方便恢复

1、存储原理

如下图,将一个矩阵中的非0值存储为三元格式的数组,数组的第一行保存稀疏矩阵的行数、列数、默认值;后面开始保存非默认值的行索引、列索引、数值

2、代码实现

package mainimport ("bufio""fmt""io/ioutil""os""strconv""strings"
)type Node struct {row intcol intval int
}const rows, cols = 6, 7func Matrix_Conver(arr [rows][cols]int, default_val int) []Node {var node []Nodenode = append(node, Node{rows, cols, default_val})for i, ar := range arr {for j, val := range ar {if val != default_val {node = append(node, Node{i, j, val})}}}return node
}func PrintMatrix(arr [rows][cols]int) {for _, ar := range arr {for _, val := range ar {fmt.Printf("%d\t", val)}fmt.Println()}
}func main() {//1. 构造稀疏矩阵def_val := -1path := "D:/array.data"array := [rows][cols]int{{def_val, def_val, def_val, 2, def_val, def_val, def_val},{def_val, def_val, def_val, def_val, def_val, def_val, def_val},{6, def_val, def_val, def_val, def_val, def_val, def_val},{def_val, def_val, 9, def_val, def_val, def_val, 1},{def_val, def_val, def_val, def_val, def_val, def_val, def_val},{def_val, def_val, def_val, def_val, def_val, 8, def_val},}fmt.Println("original matrix:")PrintMatrix(array)//2. 转为3元切片保存node := Matrix_Conver(array, def_val)fmt.Println("\nconversion to slice:")fmt.Println(node)//3. 保存3元切片到文件中fp, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0666)if err != nil {fmt.Println("file open by create and read/write mode failed, err = ", err)return}writer := bufio.NewWriter(fp)for _, data := range node {_, err = writer.WriteString(strconv.Itoa(data.row) + "," + strconv.Itoa(data.col) + "," +strconv.Itoa(data.val) + "\n")if err != nil {fmt.Println("writer write string failed, err = ", err)return}}writer.Flush() //一定要调用才能写入到文件中fp.Close()//4. 从文件中读取内容(注意,读出来的是字符格式的数字)content, err := ioutil.ReadFile(path)if err != nil {fmt.Println("ioutil.ReadFile failed, err = ", err)return}fmt.Println("\nread all content from file:")fmt.Println(string(content))//5. 还原为稀疏矩阵str := strings.Split(string(content), "\n")default_val, err := strconv.Atoi(strings.Split(str[0], ",")[2])if err != nil {fmt.Println("strconv.Atoi failed, err = ", err)return}var matrix [rows][cols]intfor i := 0; i < len(matrix); i++ {for j := 0; j < len(matrix[0]); j++ {matrix[i][j] = default_val}}//注意,最后一行是'\n',因此str切片的最后一个字符串是空字符串""for i := 1; i < len(str)-1; i++ {elements := strings.Split(str[i], ",")val := [3]int{0}for j, s := range elements {val[j], err = strconv.Atoi(s)if err != nil {fmt.Println("strconv.Atoi failed, err = ", err)return}}matrix[val[0]][val[1]] = val[2]}fmt.Println("\nrestore matrix:")PrintMatrix(matrix)
}

3、运行结果

original matrix:
-1  -1  -1  2   -1  -1  -1
-1  -1  -1  -1  -1  -1  -1
6   -1  -1  -1  -1  -1  -1
-1  -1  9   -1  -1  -1  1
-1  -1  -1  -1  -1  -1  -1
-1  -1  -1  -1  -1  8   -1  conversion to slice:
[{6 7 -1} {0 3 2} {2 0 6} {3 2 9} {3 6 1} {5 5 8}]read all content from file:
6,7,-1
0,3,2
2,0,6
3,2,9
3,6,1
5,5,8restore matrix:
-1  -1  -1  2   -1  -1  -1
-1  -1  -1  -1  -1  -1  -1
6   -1  -1  -1  -1  -1  -1
-1  -1  9   -1  -1  -1  1
-1  -1  -1  -1  -1  -1  -1
-1  -1  -1  -1  -1  8   -1

二、队列

1、概念

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表

2、数组实现队列

缺陷:数组长度lens的是固定的,意味该方式实现的队列,最多只能插入lens次,并且每弹出一个元素,数组前面将有一个位置空闲。除非每次弹出元素后,数组整体前移,但时间复杂度太大

package mainimport ("errors""fmt"
)const maxSize = 4//前端(front)进行删除操作,后端(rear)进行插入操作
type Queue struct {arr   [maxSize]intfront intrear  int
}func InitQueue() *Queue {return &Queue{front: -1, rear: -1}
}func (this *Queue) size() int {return this.rear - this.front
}func (this *Queue) isFull() bool {return this.rear == len(this.arr)-1
}func (this *Queue) isEmpty() bool {return this.front == this.rear
}func (this *Queue) offer(num int) error {if this.rear == len(this.arr)-1 {return errors.New("Queue is full")}this.rear++this.arr[this.rear] = numreturn nil
}func (this *Queue) poll() (int, error) {if this.rear == this.front {return -1, errors.New("Queue is empty")}this.front++return this.arr[this.front], nil
}func (this *Queue) peek() (int, error) {if this.rear == this.front {return -1, errors.New("Queue is empty")}return this.arr[this.front+1], nil
}func (this *Queue) list() {if this.front == this.rear {fmt.Println("Queue is empty")return}for i := this.front + 1; i <= this.rear; i++ {fmt.Printf("arr[%d] = %d\t", i, this.arr[i])}fmt.Println()
}func main() {queue := InitQueue()fmt.Printf("创建队列, size = %d, isEmpty = %t, isFull = %t, 显示队列:\n",queue.size(), queue.isEmpty(), queue.isFull())queue.list()queue.offer(1)queue.offer(2)e, _ := queue.peek()fmt.Printf("\n插入了两个元素, size = %d, 队首元素 = [%d], 显示队列:\n",queue.size(), e)queue.list()queue.offer(3)queue.offer(4)fmt.Printf("\n插入了两个元素, size = %d, isFull = %t, 显示队列:\n",queue.size(), queue.isFull())queue.list()queue.poll()e, _ = queue.poll()f, _ := queue.peek()fmt.Printf("\n弹出了两个元素, size = %d, 最新弹出的元素 = [%d], 队首元素 = [%d], 显示队列:\n",queue.size(), e, f)queue.list()
}
创建队列, size = 0, isEmpty = true, isFull = false, 显示队列:
Queue is empty插入了两个元素, size = 2, 队首元素 = [1], 显示队列:
arr[0] = 1 arr[1] = 2 插入了两个元素, size = 4, isFull = true, 显示队列:
arr[0] = 1 arr[1] = 2 arr[2] = 3 arr[3] = 4 弹出了两个元素, size = 2, 最新弹出的元素 = [2], 队首元素 = [3], 显示队列:
arr[2] = 3 arr[3] = 4

3、数组实现循环队列

说明:为了区分队列为空和队列为满,需要预留一个位置不存放数据,以此来标记空或者满

package mainimport ("errors""fmt"
)const maxSize = 4type Circlequeue struct {arr   [maxSize]intfront intrear  int
}func InitCirclequeue() *Circlequeue {//初始化时,将第0位空置(后续位置随删除而改变),作为队列满的判断标志return &Circlequeue{front: 0, rear: 0}
}func (cq *Circlequeue) size() int {return (cq.rear + maxSize - cq.front) % maxSize
}func (cq *Circlequeue) isFull() bool {return (cq.rear+1)%maxSize == cq.front
}func (cq *Circlequeue) isEmpty() bool {return cq.rear == cq.front
}func (cq *Circlequeue) offer(num int) error {if cq.isFull() {return errors.New("queue is full")}cq.rear = (cq.rear + 1) % maxSizecq.arr[cq.rear] = numreturn nil
}func (cq *Circlequeue) poll() (int, error) {if cq.rear == cq.front {return -1, errors.New("queue is empty")}cq.front = (cq.front + 1) % maxSizereturn cq.arr[cq.front], nil
}func (cq *Circlequeue) peek() (int, error) {if cq.isEmpty() {return -1, errors.New("queue is empty")}return cq.arr[(cq.front+1)%maxSize], nil
}func (cq *Circlequeue) list() {if cq.isEmpty() {fmt.Println("queue is empty")return}tmp := cq.rearif tmp < cq.front {tmp = cq.front + maxSize}for i := cq.front + 1; i <= tmp; i++ {fmt.Printf("arr[%d] = %d\t", i%maxSize, cq.arr[i%maxSize])}fmt.Println()
}func main() {cq := InitCirclequeue()fmt.Printf("创建队列, size = %d, isEmpty = %t, isFull = %t, 显示队列:\n",cq.size(), cq.isEmpty(), cq.isFull())cq.list()cq.offer(1)cq.offer(2)e, _ := cq.peek()fmt.Printf("\n插入了两个元素, size = %d, 队首元素 = [%d], 显示队列:\n",cq.size(), e)cq.list()fmt.Println()cq.offer(3)err := cq.offer(4)if err != nil {fmt.Println("offer err, err = ", err)}fmt.Printf("插入了两个元素, size = %d, isFull = %t, 显示队列:\n",cq.size(), cq.isFull())cq.list()cq.poll()e, _ = cq.poll()f, _ := cq.peek()fmt.Printf("\n弹出了两个元素, size = %d, 最新弹出的元素 = [%d], 队首元素 = [%d], 显示队列:\n",cq.size(), e, f)cq.list()cq.offer(5)cq.offer(6)fmt.Printf("\n插入了两个元素, size = %d, isFull = %t, 显示队列:\n",cq.size(), cq.isFull())cq.list()
}
创建队列, size = 0, isEmpty = true, isFull = false, 显示队列:
queue is empty插入了两个元素, size = 2, 队首元素 = [1], 显示队列:
arr[1] = 1 arr[2] = 2 offer err, err =  queue is full
插入了两个元素, size = 3, isFull = true, 显示队列:
arr[1] = 1 arr[2] = 2 arr[3] = 3 弹出了两个元素, size = 1, 最新弹出的元素 = [2], 队首元素 = [3], 显示队列:
arr[3] = 3 插入了两个元素, size = 3, isFull = true, 显示队列:
arr[3] = 3 arr[0] = 5 arr[1] = 6 arr[2] = 2

三、栈

1、概念

栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

栈是允许在同一端进行插入和删除操作的特殊线性表。允许进行插入和删除操作的一端称为栈顶(top),另一端为栈底(bottom);栈底固定,而栈顶浮动;栈中元素个数为零时称为空栈。插入一般称为进栈(PUSH),删除则称为退栈(POP)。栈也称为先进后出表

2、数组实现栈

package mainimport ("errors""fmt"
)const maxSize = 4type Stack struct {arr [maxSize]int //arr[0]为栈底top int          //top指向栈顶元素的上一位
}func InitStack() *Stack {return &Stack{top: 0}
}func (st *Stack) size() int {return st.top
}func (st *Stack) isEmpty() bool {return st.top == 0
}func (st *Stack) isFull() bool {return st.top == maxSize
}func (st *Stack) push(num int) error {if st.isFull() {fmt.Println("stack is full, push is invalid!")return errors.New("stack is full")}st.arr[st.top] = numst.top++return nil
}func (st *Stack) pop() (int, error) {if st.isEmpty() {fmt.Println("stack is empty, pop is invalid!")return -1, errors.New("stack is empty")}st.top--return st.arr[st.top], nil
}func (st *Stack) peek() (int, error) {if st.isEmpty() {fmt.Println("stack is empty, pop is invalid!")return -1, errors.New("stack is empty")}return st.arr[st.top-1], nil
}func (st *Stack) search(num int) bool {for i := 0; i < st.top; i++ {if st.arr[i] == num {return true}}return false
}func (st *Stack) list() {if st.top == 0 {fmt.Println("stack is empty")return}fmt.Printf("从栈顶到栈底:  ")for i := st.top - 1; i >= 0; i-- {fmt.Printf("arr[%d] = %d\t", i, st.arr[i])}fmt.Println()
}func main() {stack := InitStack()fmt.Printf("创建栈  size = %d  isEmpty = %t  isFull = %t  显示栈:\n",stack.size(), stack.isEmpty(), stack.isFull())stack.list()stack.push(1)stack.push(2)e, _ := stack.peek()fmt.Printf("\n入栈了两个元素(1, 2)  size = %d  栈顶元素 = [%d]  显示栈:\n",stack.size(), e)stack.list()stack.push(3)stack.push(4)fmt.Printf("\n入栈了两个元素(3, 4)  size = %d  isFull = %t  显示栈:\n",stack.size(), stack.isFull())stack.list()stack.pop()e, _ = stack.pop()f, _ := stack.peek()fmt.Printf("\n弹出了两个元素  size = %d  最新弹出的元素 = [%d]  栈顶元素 = [%d]  显示栈:\n",stack.size(), e, f)stack.list()fmt.Printf("判断元素是否在栈中:  [3] = %t  [1] = %t\n", stack.search(3), stack.search(1))
}
创建栈  size = 0  isEmpty = true  isFull = false  显示栈:
stack is empty入栈了两个元素(1, 2)  size = 2  栈顶元素 = [2]  显示栈:
从栈顶到栈底:  arr[1] = 2    arr[0] = 1 入栈了两个元素(3, 4)  size = 4  isFull = true  显示栈:
从栈顶到栈底:  arr[3] = 4    arr[2] = 3 arr[1] = 2 arr[0] = 1 弹出了两个元素  size = 2  最新弹出的元素 = [3]  栈顶元素 = [2]  显示栈:
从栈顶到栈底:  arr[1] = 2    arr[0] = 1
判断元素是否在栈中:  [3] = false  [1] = true

Go语言学习笔记【11】 数据结构之稀疏矩阵、队列、栈相关推荐

  1. C语言学习笔记06-占位符格式、C基本类型及逃逸字符一些细节(附介绍BCD码)

    主要整理有关占位符格式与逃逸字符的一些细节 朋友们,看栗子--"BCD解码" (文末附BCD码介绍) 一个BCD数的十六进制是0x12(对应二进制表示:0001 0010),它表达 ...

  2. R语言学习笔记(1~3)

    R语言学习笔记(1~3) 一.R语言介绍 x <- rnorm(5) 创建了一个名为x的向量对象,它包含5个来自标准正态分布的随机偏差. 1.1 注释 由符号#开头. #函数c()以向量的形式输 ...

  3. 【Go语言 · 学习笔记】

    文章目录 Go语言 · 学习笔记 一.Go包管理 1. 什么是Go语言中的包 2. 包的命名 3. main包 4. 导入包 5. 远程包导入 6. 命名导入 7. 包的init函数 二.Go开发工具 ...

  4. 嵌入式C语言——学习笔记

    嵌入式C语言--学习笔记 计算机程序语言的学习思路? GCC的使用及其常用选项介绍 gcc概述 C语言编译过程 C语言常见的错误 预处理的使用 宏展开下的 #.## C语言常用关键字及运算符操作 关键 ...

  5. 易语言学习笔记(2)

    易语言学习笔记(2) 1 数据类型 1.1 基本数据类型 1.1.1 数值型 1.2 特殊数据类型 1.3 数据类型长度 1.4 各数据类型初始值 1.5 数据类型间转换命令 2 易语言的命令 2.1 ...

  6. c语言中void arrout,c语言学习笔记(数组、函数

    <c语言学习笔记(数组.函数>由会员分享,可在线阅读,更多相关<c语言学习笔记(数组.函数(53页珍藏版)>请在人人文库网上搜索. 1.数组2010-3-29 22:40一维数 ...

  7. python的基本数据结构_Python学习笔记——基本数据结构

    列表list List是python的一个内置动态数组对象,它的基本使用方式如下: shoplist = ['apple', 'mango', 'carrot', 'banana'] print 'I ...

  8. go get 拉取指定版本_go语言学习笔记-基础知识-3

    相关文档 go语言学习笔记-目录 1.简介 1.1 什么是GO Go 是一个开源的编程语言,它能让构造简单.可靠且高效的软件变得容易.Go是从2007年末由Robert Griesemer, Rob ...

  9. c语言如何宏定义枚举型结构体,C语言学习笔记--枚举结构体

    枚举 枚举是一种用户定义的数据类型,它用关键字enum以如下语法格式来声明: enum 枚举类型名字 {名字0,名字1,...,名字n}: 枚举类型名字通常并不真的使用,要用的是大括号里面的名字,因为 ...

  10. r语言c函数怎么用,R语言学习笔记——C#中如何使用R语言setwd()函数

    在R语言编译器中,设置当前工作文件夹可以用setwd()函数. > setwd("e://桌面//") > setwd("e:\桌面\") > ...

最新文章

  1. 【Java】环形链表 ( 给定一个链表,判断链表中是否有环)
  2. c++ 异步回调_知道Java中的回调机制吗?
  3. 危机边缘第一季/全集Fringe迅雷下载
  4. 【Network Security!】5次Shift漏洞和PE系统
  5. face key point with 7 points
  6. Python机器学习——线性模型
  7. 几何着色器与细分(镶嵌)着色器
  8. 来自Riot 的一份游戏美术教程(三):角色设计
  9. c++ 舞伴配对问题_挑战新物体描述问题,视觉词表解决方案超越人类表现
  10. HTK下yes/no的识别
  11. Matplotlib - bar(条形图)
  12. Computer Vision: Algorithms and Applications阅读笔记
  13. svn 服务器端密码修改,svn服务器端设置密码
  14. ab 与 abs 测试详解
  15. php太平洋时间转成北京时间,太平洋时间和北京时间换算(太平洋时间现在几点)...
  16. 【跨域】 关于跨域的一些知识整合
  17. 低功耗蓝牙芯片CH579系列开发记录
  18. 台式计算机硬件组成主机,台式电脑主机的硬件组成部分简介
  19. PC天翼云盘v6.3.4精简版
  20. python官网各个版本下载地址

热门文章

  1. 天狼星ID:推动区块链上的自我主权时代
  2. 小米note2开启位置服务器,小米note2如何解锁system系统分区教程_小米note2解系统分区...
  3. NetSuite 简介
  4. 攻防演练中攻击方是如何打开缺口的方法——总结
  5. linux minit 截图,带有屏幕截图的Linux Mint 19.2代号“ Tina”的安装指南
  6. 新品发布 | 信驰达发布基于Nordic nRF52833的BLE模块RF-BM-ND10
  7. 四川理工c语言实验报告,多普勒综合实验报告.docx
  8. 支小蜜智慧食堂刷脸支付系统,全面提升食堂管理水平
  9. 九二、node+cheerio爬虫学习
  10. C#+Midi 模拟各种乐器演奏