数据结构
数据结构是一门研究算法的学科,只从有了编程语言也就有了数据结构.学好数据结构可以编写出更加漂亮,更加有效率的代码。
程序=数据结构+算法
稀疏数组
当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。
稀疏数组的处理方法是:
1) 记录数组一共有几行几列,有多少个不同的值
2) 把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模
应用实例
1)使用稀疏数组,来保留类似前面的二维数组(棋盘、地图等等)
2)把稀疏数组存盘,并且可以从新恢复原来的二维数组数
3)整体思路分析
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)
}
}
}
//输出稀疏数组
fmt.Println("当前的稀疏数组是::::")
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
//遍历sparseArr [遍历文件每一行]
for i,valNode := range sparseArr {
if i != 0 { //跳过第一行记录值
chessMap2[valNode.row][valNode.col] = valNode.val
}
}
//输出恢复的chessMap2
fmt.Println("恢复后的原始数据。。。。。")
for _,v := range chessMap {
for _,v2 := range v {
fmt.Printf("%d\t",v2)
}
fmt.Println()
}
}
队列
队列是一个有序列表,可以用数组或是链表来实现。
遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出
数组模拟队列(不是环形)
1.队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下其中maxSize是该队列的最大容量。
2.因为队列的输出、输入是分别从前后端来处理,因此需要两个变量front及rear分别记录队列前后端的下标,front 会随着数据输出而改变,而rear则是随着数据输入而改变,如图所示:
当我们将数据存入队列时称为”addqueue",addqueue 的处理需要有两个步骤:
1)将尾指针往后移: rear+1 , front == rear【空】
2)若尾指引rear小于等于队列的最大下标 MaxSize-1,则将数据存入 rear所指的数组元素中,否则无法存入数据。rear ==MaxSize-1[队列满]
package main
import (
"fmt"
"os"
"errors"
)
//使用结构体管理队列
type Queue struct {
maxSize int
array [5]int //数组--》模拟队列
front int //表示指向队列首
rear int //表示指向队列的尾部
}
//添加数据到队列
func(this *Queue)AddQueue(val int)(err error){
//先判断队列事是否已满
if this.rear == this.maxSize -1 { //重要提示,rear 是队列尾部(含最后的元素)
return errors.New("queue full")
}
this.rear++ //rear后移
this.array[this.rear]=val
return
}
//显示队列
func(this *Queue)ShowQueue(){
fmt.Println("队列当前的情况是: ")
//this.Front 不包含队首的元素
for i := this.front+1;i<=this.rear;i++{
fmt.Printf("array[%d]=%d \t",i,this.array[i])
}
fmt.Println()
}
//从队列中取出数据
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 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(err.Error())
}else{
fmt.Println("加入队列ok")
}
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)
default:
fmt.Println("输入错误,请重新输入")
}
}
}
数组模拟环形队列
对前面的数组模拟队列的优化,充分利用数组.因此将数组看做是一个环形的。(通过取模的方式来实现即可)
注意:
1) 尾索引的下一个为头索引时表示队列满,即将队列容量空出一个作为约定,这个在做判断队列满的时候需要注意.( tail+ 1) % maxSize == head [满]
2) tail == head表示空
3)初始化时,tail = 0 head= 0
4)怎么统计该队列有多少个元素 (tail + maxSize - head ) % maxSize
package main
import (
"fmt"
"os"
"errors"
)
//使用一个结构体管理环形队列
type CircleQueue struct {
maxSize int //5
array [5]int //数组
head int // 指向队列的头 0
tail int //指向队列的尾 0
}
//入队列ADDQueue(push) GetQueue(pup)
func (this *CircleQueue) Push(val int)(err error){
if this.IsFull() {
return errors.New("queue full")
}
//分析出this.tail 在队列尾部,但是包含最后的元素
this.array[this.tail] = val //把值给尾部
this.tail=(this.tail+1)%this.maxSize //===tail++
return
}
//出队列
func (this *CircleQueue) Pop()(val int,err error){
if this.IsEmpty(){
return 0,errors.New("queue empty")
}
//取出 head 是指向队首,并且包含队首元素
val = this.array[this.head]
this.head=(this.head+1)%this.maxSize //===head++
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
}
fmt.Println()
}
//判断环形队列为满
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(err.Error())
}else{
fmt.Println("加入队列ok")
}
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)
default:
fmt.Println("输入错误,请重新输入")
}
}
}