稀疏数组(sparsearray)
稀疏数组介绍
当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。
稀疏数组的处理方法
- 记录数组一共有几行几列,有多少个不同的值
- 把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模
案例
package main
import "fmt"
type ValNode struct {
row int
col int
val int
}
func main() {
//1. 先创建一个原始数组
var chessMap [11][11]int
chessMap[1][2] = 1 //黑子
chessMap[2][3] = 2 //蓝子
// 2. 输出原始的数组
for _, v := range chessMap {
for _, v2 := range v {
fmt.Printf("%d\t", v2)
}
fmt.Println()
}
//3. 转成稀疏数组
//思路:
//(1)遍历chessMap,如果我们发现有一个元素的值不为0,创建士个node结构体
//(2).将其放入到对应的切片即可
var sparseArr []ValNode
//标准的一个稀疏数组应该还有一个记录元素的二维数组的规模(行和列,默认值)
valNode := ValNode{
row: 11,
col: 11,
val: 0,
}
sparseArr = append(sparseArr, valNode)
for i, v := range chessMap {
for j, v2 := range v {
if v2 != 0 {
//创建一个ValNode 值结点
valNode := ValNode{
row: i,
col: j,
val: v2,
}
sparseArr = append(sparseArr, valNode)
}
}
}
//输出稀疏数组
for i, valNode := range sparseArr {
fmt.Printf("%d: %d %d %d\n", i, valNode.row, valNode.col, valNode.val)
}
//将稀疏数组,存盘 d:/chessmap.data
//恢复原始数据
//1.打开这个d:/chessmap.data =>恢复原始数组.
//2. 这里使用稀疏数组恢复
//先创建一个原始数据
var chessMap2 [11][11]int
//遍历
for i, valNode := range sparseArr {
if i != 0 {
chessMap2[valNode.row][valNode.col] = valNode.val
}
}
for _, v := range chessMap2 {
for _, v2 := range v {
fmt.Printf("%d\t", v2)
}
fmt.Println()
}
}
队列
队列是一个有序列表,可以用数组或是链表来实现。
遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出
数组模拟队列
队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下其中maxsize是该队列的最大容量。
因为队列的输出、输入是分别从前后端来处理,因此需要两个变量front及rear分别记录队列前后端的下标,front 会随着数据输出而改变,而rear则是随着数据输入而改变.
package main
import (
"errors"
"fmt"
"os"
)
//使用一个结构体管理队列
type Queue struct {
array [5]int
front int
rear int
maxSize int
}
func (this *Queue) AddQueue(val int) (err error) {
//先判断队列是否已满
if this.rear == this.maxSize-1 {
return errors.New("queue full")
}
this.rear++
this.array[this.rear] = val
return
}
func (this *Queue) GetQueue() (val int, err error) {
if this.rear == this.front {
return -1, errors.New("queue empty")
}
this.front++
val = this.array[this.front]
return val, err
}
func (this *Queue) ShowQueue() {
for i := this.front + 1; i <= this.rear; i++ {
fmt.Printf("arrary[%d] = %d\t", i, this.array[i])
}
fmt.Println()
}
func main() {
queue := &Queue{
maxSize: 5,
front: -1,
rear: -1,
}
var key string
var val int
for {
fmt.Println("1. 输入add 表示添加数据到队列")
fmt.Println("2. 输入get 表示从队列获取数据")
fmt.Println("3. 输入show 表示显示队列")
fmt.Println("4. 输入exit 表示退出队列")
fmt.Scanln(&key)
switch key {
case "add":
fmt.Println("输入你要如队列数:")
fmt.Scanln(&val)
err := queue.AddQueue(val)
if err == nil {
fmt.Println("加入队列成功")
} else {
fmt.Println(err.Error())
}
case "get":
val, err := queue.GetQueue()
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println("取出了这个数", val)
}
case "show":
queue.ShowQueue()
case "exit":
os.Exit(0)
}
}
}
上面代码实现了基本队列结构,但是没有有效的利用数组空间
数组模拟环形队列
对前面的数组模拟队列的优化,充分利用数组.因此将数组看做是一个环形的。(通过取模的方式来实现即可)
尾索引的下一个为头索引时表示队列满,即将队列容量空出一个作为约定,这个在做判断队列满的时候需要注意.
- (tail + 1) %maxSize == head [满]
- tail == head [空]
- 初始化时,tail = 0 head=0
- 怎么统计该队列有多少个元素(tail + maxSize - head) % maxSize
package main
import (
"errors"
"fmt"
"os"
)
//使用一个结构体管理环形队列
type CircleQueue struct {
maxSize int
array [5]int
head int
tail int
}
func (this *CircleQueue) Push(val int) (err error) {
if this.IsFull() {
return errors.New("queue full")
}
this.array[this.tail] = val
this.tail = (this.tail + 1) % this.maxSize
return
}
func (this *CircleQueue) Pop() (val int, err error) {
if this.IsEmpty() {
return 0, errors.New("queue empty")
}
val = this.array[this.head]
this.head = (this.head + 1) % this.maxSize
return
}
func (this *CircleQueue) ListQueue() {
//取出当前队列有多少元素
size := this.Size()
if size == 0 {
fmt.Println("队列为空")
}
tempHead := this.head
for i := 0; i < size; i++ {
fmt.Printf("arr[%d] = %d \t", tempHead, this.array[tempHead])
tempHead = (tempHead + 1) % this.maxSize
}
}
func (this *CircleQueue) IsFull() bool {
return (this.tail+1)%this.maxSize == this.head
}
func (this *CircleQueue) IsEmpty() bool {
return this.tail == this.head
}
func (this *CircleQueue) Size() int {
return (this.tail + this.maxSize - this.head) % this.maxSize
}
func main() {
queue := CircleQueue{
maxSize: 5,
head: 0,
tail: 0,
}
var key string
var val int
for {
fmt.Println("1. 输入add 表示添加数据到队列")
fmt.Println("2. 输入get 表示从队列获取数据")
fmt.Println("3. 输入show 表示显示队列")
fmt.Println("4. 输入exit 表示退出队列")
fmt.Scanln(&key)
switch key {
case "add":
fmt.Println("输入你要如队列数:")
fmt.Scanln(&val)
err := queue.Push(val)
if err == nil {
fmt.Println("加入队列成功")
} else {
fmt.Println(err.Error())
}
case "get":
val, err := queue.Pop()
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println("取出了这个数", val)
}
case "show":
queue.ListQueue()
case "exit":
os.Exit(0)
}
}
}