数据结构

稀疏数组

package main

import "fmt"

/*
稀疏数组
案例:五子棋存盘与复盘
节省存储空间
*/
type ValNode struct {
row int //行
col int //列
val int //值
} //原始数组实现
func normalArray() {
var chessMap [][]int
chessMap[][] = //黑子
chessMap[][] = //白子
//输出
for _, v := range chessMap {
for _, v2 := range v {
fmt.Printf("%d ", v2)
}
fmt.Println()
}
} //稀疏数组实现 func sparseArray() {
//数据源
var chessMap [][]int
chessMap[][] = //黑子
chessMap[][] = //白子
//切片
var sparseArr []ValNode
//创建一个ValNode节点
valNode := ValNode{
row: ,
col: ,
val: ,
}
//输入全局默认节点
sparseArr = append(sparseArr, valNode)
for i, v := range chessMap {
for j, v2 := range v {
//创建一个节点
if v2 != {
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)
}
var chessMap2 [][]int
//稀疏数组恢复原始数组
for i, valNode := range sparseArr {
//跳过第一行默认记录值
if i != {
chessMap2[valNode.row][valNode.row] = valNode.val
}
}
//输出恢复后的数组
for _,v:=range chessMap2{
for _,v2:=range v{
fmt.Printf("%d ",v2)
}
fmt.Println()
}
} func main() {
sparseArray()
}

队列

使用数据模拟队列

package main

import (
"errors"
"fmt"
"os"
) //使用结构体管理队列
type Queue struct {
maxSize int
array []int //数组=》模拟队列
front int //表示指向队首
rear int //表示指向队尾
} //添加数据到队列
func (this *Queue) AddQueue(val int) (err error) {
//先判断队列是否已满
if this.rear == this.maxSize- { //重要提示,rear是队列尾部(含最后元素
return errors.New("queue full")
}
//元素从下标为1开始存入
this.rear++ //后移
//存入元素
this.array[this.rear] = val
return
} //从队列中取出元素
func (this *Queue) GetQueue() (val int, err error) {
//先判断队列是否为空
if this.rear == this.front { //队列
return -, errors.New("queue empty")
} this.front++
val = this.array[this.front]
return val, err
} //显示队列,找到队首,然后遍历到队尾 func (this *Queue) ShowQueue() {
fmt.Println("队列当前的情况是:")
//this.front//不包含队首
for i := this.front + ; i <= this.rear; i++ {
fmt.Printf("array[%d]=%d\t", i, this.array[i])
}
} func main(){
//创建一个队列
queue:=&Queue{
maxSize: ,
array: []int{},
front: -,
rear: -,
}
var key string
var val int
for{
fmt.Println("\n\n1.输入add表示添加数据到队列")
fmt.Println("2.输入get表示从队列获取数据")
fmt.Println("3.输入show表示显示队列")
fmt.Println("4.输入exit表示退出\n\n")
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.Print("加入队列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()
}
} }

通过数组实现环形队列

package main

import (
"errors"
"fmt"
"os"
) //数组模拟环形队列
/*
1.尾索引下一个为头索引时表示队列满,即将队列容量空出一个作为约定,这个在做判断队列满的时候需要注意
(tail+1)%maxSize==head满
2.tail==head [空]
*/ type CircleQueue struct {
maxSize int //
array []int //数组
head int //指向队首0
tail int //指向队尾0
} //入队
func (this *CircleQueue) Push(val int) (err error) {
if this.IsFull() {
return errors.New("queue full")
}
//分析指出this.tail 在队列尾部,但是包含最后的元素
this.array[this.tail] = val //把值给队尾
//如果当前行满。回到行初开始(加1是因为下标从零开始)
this.tail = (this.tail + ) % this.maxSize
return
} //出队
func (this *CircleQueue) Pop() (val int, err error) {
if this.IsEmpty() {
return , errors.New("queue empty")
}
//取出head指向队首,并且含队首元素
val = this.array[this.head]
//%如果满行回到行首
this.head = (this.head + ) % this.maxSize
return
} //显示队列
func (this *CircleQueue) ListQueue() {
fmt.Println("环形队列情况如下")
//取出当前队列有多少个元素
size := this.Size()
if size == {
fmt.Println("队列为空")
}
//设计一个辅助便理那个指向head
tempHead := this.head
for i := ; i < size; i++ {
fmt.Printf("arr[%d]=%d\t", tempHead, this.array[tempHead])
tempHead = (tempHead + ) % this.maxSize
}
fmt.Println()
} //判断队列为满
func (this *CircleQueue) IsFull() bool {
//队尾之前的长度%总长度=队首之后的长度
return (this.tail+)%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
}
/*
1.队尾在队首之后
this.tail% this.maxSize + this.maxSize% this.maxSize - this.head% this.maxSize
队尾之前的长度+1-队首之前的长度=总长度
*/ func main() {
cq := CircleQueue{
maxSize: ,
array: []int{},
head: ,
tail: ,
}
var key string
var val int
for {
fmt.Println("\n\n1.输入add表示添加数据到队列")
fmt.Println("2.输入get表示从队列获取数据")
fmt.Println("3.输入show表示显示队列")
fmt.Println("4.输入exit表示退出\n\n")
fmt.Scanln(&key)
switch key {
case "add":
fmt.Println("请输入入队的数:")
fmt.Scanln(&val)
err := cq.Push(val)
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println("入队成功")
}
case "get":
val, err := cq.Pop()
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Printf("出队成功:%d", val)
}
case "show":
cq.ListQueue()
case "exit":
os.Exit()
default:
fmt.Println("输入错误")
}
}
}

链表

单向链表

package main

import "fmt"

/*
单向链表的应用
水浒英雄排行榜
*/ type HeroNode struct {
no int
name string
nickname string
next *HeroNode //表示指向下一个节点
} //给链表插入一个节点
//编写第一个插入方法,在单链表最后加入 func InsertHeroNode(head *HeroNode, newHeroNode *HeroNode) {
temp := head
for {
if temp.next == nil { //表示找到最后
break
}
temp = temp.next //让temp不断指向下一个节点
}
//3.将newHeroNode加入到链表最后
temp.next = newHeroNode
} //第二种插入方法,根据no的编号从小到大插入
func InsertHeroNode2(head *HeroNode, newHreoNode *HeroNode) {
//1.找到适当的节点
temp := head
flag := true
//让插入的节点的no,和temp的下一个结点比较
for {
if temp.next == nil { //说明到了链表最后
break
} else if temp.next.no >= newHreoNode.no {
//说明newHeroNode就应该插入到temp后面
break
} else if temp.next.no == newHreoNode.no {
//说明链表中已经有这个no,就不插入
flag = false
break
}
//不断寻找下一个结点
temp = temp.next
} if !flag {
fmt.Println("对不起,已经存在no=", newHreoNode.no)
return
} else {
newHreoNode.next = temp.next
temp.next = newHreoNode
}
} //显示所有链表节点信息
func ListNode(head *HeroNode) {
//1.创建一个辅助结点
temp := head
//先判断该链表是不是一个空链表
if temp.next == nil {
fmt.Println("空空如也。。。")
return
}
//2.遍历这个链表
for {
fmt.Printf("[%d,%s,%s==>", temp.next.no,
temp.next.name, temp.next.nickname)
//判断是否链表后
temp = temp.next
if temp.next == nil {
break
}
}
} //删除结点
func DelHeroNode(head *HeroNode, id int) {
temp := head
flag := false
//找到要删除的结点,和temp的下一个结点的no比较
for {
if temp.next == nil { //说明到链表最后
break
} else if temp.next.no == id {
//找到了
flag = true
break
}
temp = temp.next
}
if flag {
temp.next = temp.next.next
} else {
fmt.Println("sorry,要删除的id,不存在")
}
}
func main() {
//1.先创建一个头结点
head := &HeroNode{}
//2.创建一个新的HeroNode
hero1 := &HeroNode{
no: ,
name: "宋江",
nickname: "及时雨",
} hero2 := &HeroNode{
no: ,
name: "卢俊义",
nickname: "玉麒麟",
} hero3 := &HeroNode{
no: ,
name: "林冲",
nickname: "豹子头",
} hero4 := &HeroNode{
no: ,
name: "吴用",
nickname: "智多星",
}
InsertHeroNode(head, hero4)
InsertHeroNode(head, hero1)
InsertHeroNode(head, hero2)
InsertHeroNode(head, hero3) ListNode(head)
//3.加入
//InsertHeroNode2(head, hero3)
//InsertHeroNode2(head, hero1)
//InsertHeroNode2(head, hero2)
//InsertHeroNode2(head, hero4)
////4.显示
//ListNode(head)
}

双向链表

package main

import "fmt"

type HeroNode struct {
no int
name string
nickname string
pre *HeroNode //这个结点指向前一个结点
next *HeroNode //着这结点指向下一个结点
} //给双向链表插入一个结点
func InsertHeroNode(head *HeroNode, newHeroNode *HeroNode) {
//思路
//1.先找到该链表的最后这个结点
//2.创建一个辅助结点
temp := head
for {
if temp.next == nil {
break
}
temp = temp.next //让temp不断指向下一个结点
}
//3.将newHeroNode加入到链表的最后
temp.next = newHeroNode
newHeroNode.pre = temp
} //给双向链表插入一个结点
//
func InsertHeroNode2(head *HeroNode, newHeroNode *HeroNode) {
//1.找到适当的结点
//2.创建一个辅助结点
temp := head
flag := true
//让插入结点的no,和temp的下一个结点的no比较
for {
if temp.next == nil {
break
} else if temp.next.no >= newHeroNode.no {
//说明newHeroNode就因该插入到temp后面
break
} else if temp.next.no >= newHeroNode.no {
flag = false
break
}
temp = temp.next
} if !flag {
fmt.Println("对不起,已经存在no=", newHeroNode.no)
return
} else {
newHeroNode.next = temp.next
newHeroNode.pre = temp
if temp.next != nil { //不是最后一个才进行操作
temp.next.pre = newHeroNode
}
temp.next = newHeroNode }
} //删除结点
func DelHeroNode(head *HeroNode, id int) {
temp := head
flag := true
//找到要删除的结点的no,和temp的下一个结点no比较
for {
if temp.next == nil {
break
} else if temp.next.no == id {
//说明找到了
flag = true
break
}
temp = temp.next
} if flag {
temp.next = temp.next.next
if temp.next != nil {
temp.next.pre = temp
} else {
fmt.Println("sorry, 要删除的id不存在")
}
}
} //使用单链表的显示方式显示链表
func ListHeroNode(head *HeroNode) {
//1.辅助结点
temp := head
if temp.next == nil {
fmt.Println("空空如也。。。")
return
}
//遍历链表
for {
fmt.Printf("[%d,%s,%s]=>", temp.next.no,
temp.next.name, temp.next.nickname)
//判断是否链表
temp = temp.next
if temp.next == nil {
break
}
}
} //方式二
//使用单链表的显示方式显示链表
func ListHeroNode2(head *HeroNode) {
//1.辅助结点
temp := head
if temp.next == nil {
fmt.Println("空空如也。。。")
return
}
//2.让temp定位到双向链表的最后结点
for {
if temp.next == nil {
break
}
temp = temp.next
} //遍历链表
for {
fmt.Printf("[%d,%s,%s]=>", temp.no,
temp.name, temp.nickname)
//判断是否链表
temp = temp.pre
if temp.pre == nil {
break
}
}
} func main() {
//1.先创建一个头结点
head := &HeroNode{}
//2.创建一个新的HeroNode
hero1 := &HeroNode{
no: ,
name: "宋江",
nickname: "及时雨",
} hero2 := &HeroNode{
no: ,
name: "卢俊义",
nickname: "玉麒麟",
} hero3 := &HeroNode{
no: ,
name: "林冲",
nickname: "豹子头",
} hero4 := &HeroNode{
no: ,
name: "吴用",
nickname: "智多星",
}
InsertHeroNode(head, hero1)
InsertHeroNode(head, hero2)
InsertHeroNode(head, hero3)
InsertHeroNode(head, hero4)
ListHeroNode(head)
fmt.Println("\n逆序打印")
ListHeroNode2(head) }

环形单向链表

package main

import "fmt"

/*
环形单向链表 */
//定义猫的结构体结点
type CatNode struct {
no int //编号
name string
next *CatNode
} //在末尾加入新的结点
func InsertCatNode(head *CatNode, newCatNode *CatNode) {
//判断是不是添加第一只猫
if head.next == nil {
head.no = newCatNode.no
head.name = newCatNode.name
head.next = head //构成一个环形
fmt.Println(newCatNode, "加入到环形链表")
return
} //定义一个临时变量,帮忙找到环形的最后结点
temp := head
for {
if temp.next == head {
break
}
temp = temp.next
}
//加入到链表中
temp.next = newCatNode
newCatNode.next = head
} //输出这个环形链表
func ListCircleLink(head *CatNode) {
fmt.Println("环形链表的情况如下")
temp := head
if temp.next == nil {
fmt.Println("空空如也的环形链表。。")
return
}
//循环输出
for {
fmt.Printf("猫的信息为=[id=%d name=%s]->\n", temp.no, temp.name)
if temp.next == head { //到结尾就跳出
break
}
//进入下一个结点
temp = temp.next
}
} //删除一个节点
func DelCatNode(head *CatNode, id int) *CatNode {
temp := head
helper := head
//空链表
if temp.next == nil {
fmt.Println("这是一个空的环形链表,不能删除")
return head
}
//如果只有一个结点
if temp.next == head {
if temp.no == id {
temp.next = nil //执行删除
fmt.Printf("删除猫猫=%d\n", id)
}
return head
}
//将helper定位到链表最后
for {
if helper.next == head {
break
}
helper = helper.next
}
//到这里为止helper为最后一个结点,temp为头结点,也就是说helper是temp前面一个结点。在循环中两者的关系始终相邻。
//head为头结点 //如果有两个包含两个以上的结点
flag := true
for {
//循环到结尾,跳出
if temp.next == head { //如果到这来,说明我们比较到最后一个[最后一个还没比较]
break
} //找到结点
if temp.no == id {
//目标是头结点
if temp == head { //说明删除的是头结点
head = head.next //删除头结点
}
//目标是其他结点
//恭喜找到,我们也可以直接删除
helper.next = temp.next //执行删除,如果helper.no为2,temp.no为3,此时删除的是3 fmt.Printf("删除猫猫=%d\n", id)
flag = false
break
}
//继续循环,类似i++,两个结点同步循环
temp = temp.next //移动
helper = helper.next //移动
} //flag为true表示没找到
if flag {
fmt.Printf("对不起,没有no=%d\n", id)
}
return head
} func main() {
//初始化一个环形链表的头节点
head := &CatNode{}
//创建一只猫
cat1 := &CatNode{
no: ,
name: "tom",
}
cat2 := &CatNode{
no: ,
name: "tom2",
}
cat3 := &CatNode{
no: ,
name: "tom3",
}
cat4 := &CatNode{
no: ,
name: "tom4",
} InsertCatNode(head, cat1)
InsertCatNode(head, cat2)
InsertCatNode(head, cat3)
InsertCatNode(head, cat4)
ListCircleLink(head)
head = DelCatNode(head, )
fmt.Println()
fmt.Println()
fmt.Println()
fmt.Println()
ListCircleLink(head) }

环形单向链表应用

package main

import "fmt"

/*
环形单项链表的应用 问题为:设编号为1, 2,... n的n个人围坐一圈,约定编号为k (1<=k<=n) 的人从1
台报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,
直到所有人出列为止,由此产生个出队编号 的序列。
*/ //小孩的结构体
type Boy struct {
No int //编号
Next *Boy //指向下一个小孩的指针【默认值是nil】
} //编写一个函数,构成单向的环形链表
//num:表示小孩的个数
//*Boy:返回该环形链表的第一个小孩的指针
func AddBoy(num int) *Boy {
first := &Boy{} //空结点
curBoy := &Boy{} //空结点
//判断
if num < {
fmt.Println("num的值不对")
return first
}
//循环的构建这个环形链表
for i := ; i <= num; i++ {
boy := &Boy{
No: i,
}
//分析构成循环链表,需要一个辅助指针
//1.因为第一个小孩比较特殊
if i == { //第一个小孩
first = boy //不要动
curBoy = boy //curBoy默认为第一个小孩
curBoy.Next = first //第一个小孩自成链表 } else {
curBoy.Next = boy //链接上前面的
curBoy = boy //保存当前小孩留待下次循环使用
curBoy.Next = first //链接上后面的,构成环形链表
}
}
return first //返回头结点
} //显示单向的环形链表【遍历】
func ShowBoy(first *Boy) {
//处理一下如果环形链表为空
if first.Next == nil {
fmt.Println("链表为空,没有小孩")
return
}
//创建一个指针,帮助遍历。[说明至少有一个小孩]
curBoy := first
for {
fmt.Println("小孩编号=%d->", curBoy.No)
//退出的条件?curBoy.Next==first
if curBoy.Next == first { //循环到最后一个结束
break
}
//curBoy//移动到下一个
curBoy = curBoy.Next
}
} /*
设编号为1,2,。。n的n个人未做一圈,约定编号为k(1<=k<=n)
的人从1开始报数,数到m的那个出列,它的下一位又从1开始报数。
数到m的那个人又出列,一次类推,直到所有人出列为止,由此产生一个出列编号的序列 */
//分析思路
//1.编写一个函数,PlayGame(first *Boy,startNo int,countNum int)
//2.最后我们使用一个算法,按照要求,在环形链表中留下最后一个人 func PlayGame(first *Boy, startNo int, countNum int) {
//1.空的链表我们单独处理
if first.Next == nil {
fmt.Println("空的链表,没有小孩")
return
}
//留一个,判断startNo<=小孩总数
//2.需要定义的辅助指针,帮助我们删除小孩
tail := first
//3.让tail执行环形链表的最后一个小孩,这个非常的重要
//因为tail在删除小孩时需要使用到
for {
if tail.Next == first { //说明tail到了最后的小孩
break
}
tail = tail.Next //获取尾结点
}
//4.让first移动到startNo后面我们删除小孩,就以first为准
for i := ; i <= startNo-; i++ {
first = first.Next
tail = tail.Next
} //保持顺序推进到开始结点
fmt.Println()
//.开始数countNum,然后删除first指向的小孩
for {
//开始数countNum-1次
for i := ; i <= countNum-; i++ {
first = first.Next
tail = tail.Next
}
fmt.Printf("小孩编号为%d 出圈\n", first.No)
//删除first执行大小孩
first = first.Next //链接后面的新的,同时表示删除
//tail始终是first前面一个
tail.Next = first //把first前面的链接上
//判断如果tail==first,圈子中只有一个小孩
if tail == first {
break
}
}
fmt.Printf("小孩编号为%d出圈\n", first.No)
}
func main() {
first := AddBoy()
//显示
ShowBoy(first)
PlayGame(first, , ) }

算法

排序

package main

import (
"fmt"
) /*
选择排序
*/
func SelectSort(arr *[]int) {
for j := ; j < len(arr)-; j++ {
max := arr[j]
maxIndex := j
//每一次都找到全局最大值,放到前面
for i := j + ; i < len(arr); i++ {
if max < arr[i] { //找到真正最大值
max = arr[i]
maxIndex = i
}
}
//交换
if maxIndex != j {
arr[j], arr[maxIndex] = arr[maxIndex], arr[j]
}
fmt.Printf("第%d次%v\n", j+, *arr) }
} /*
插入排序
*/
func InsertSort(arr *[]int) {
//完成第一次,给第二个元素找到合适的位置并插入
for i := ; i < len(arr); i++ {
insertVal := arr[i]
insertIndex := i - //下标
//如果后面的值大于前面的值,进行交换
//对i前面的数,从右向左,一次相邻作比较,大的放前面,同时数据后移
for insertIndex >= && arr[insertIndex] < insertVal {
fmt.Printf("arr[%v]=%v<%v\n", insertIndex, arr[insertIndex], insertVal)
arr[insertIndex+] = arr[insertIndex] //数据后移
insertIndex--
}
//插入
if insertIndex+ != i {
fmt.Printf("insertIndex=%v\n", insertIndex)
arr[insertIndex+] = insertVal
}
fmt.Printf("第%d次插入后 %v\n", i, *arr)
}
} /*
快速排序法
*/
//说明
//1.left表示数组左边的下标
//2.right表示数组右边的下标
//3.array表示要排序的数组
func QuickSort(left int, right int, array *[]int) {
l := left
r := right
//pivot是中轴,支点
pivot := array[(left+right)/]
temp :=
//for循环的目标是将此pivot小的数放到左边
//比pivot大的数放到右边
for ; l < r; {
//从pivot的左边找到大于等于pivot的值
for ; array[l] < pivot; {
l++
}
//从pivot的upibian找到小于等于pivot的值
for ; array[r] > pivot; {
r--
}
//l<=r 表明本次分解任务完成,nreak
if l >= r {
break
}
//交换
temp = array[l]
array[l] = array[r]
array[r] = temp
//优化
if array[l] == pivot {
r--
}
if array[r] == pivot {
l++
}
}
//如果 lr,再移动下
if l == r {
l++
r--
}
//向左递归
if left < r {
QuickSort(left, r, array)
}
//向右递归
if right > l {
QuickSort(l, right, array)
}
}
func main() {
//arr:=[6]int{2,34,56,678,3,4}
//SelectSort(&arr) //iarr := [7]int{2, 354, 67, 5, 687, 22, 343}
//InsertSort(&iarr) arr:=[]int{-,,,,-,,,,-}
fmt.Println("初始",arr)
//调用快速排序
QuickSort(,len(arr)-,&arr)
fmt.Println("main..")
fmt.Println(arr)
}

使用数组来模拟一个栈的使用

package main

import (
"errors"
"fmt"
) //使用数组来模拟一个栈的使用
type Stack struct {
MaxTop int //表示我们栈最大可以存放的个数
Top int //表示栈顶,因为栈顶固定,因此直接使用Top
arr []int //数组模拟战
} //入栈
func (this *Stack) Push(val int) (err error) {
//判断栈是否满了
if this.Top == this.MaxTop- {
fmt.Println("stack full")
return errors.New("stack full")
}
this.Top++
//放入数据
this.arr[this.Top] = val
return
} //出栈
func (this *Stack) Pop() (val int, err error) {
//判断栈是否为空
if this.Top == - {
fmt.Println("stack empty !")
return , errors.New("stack empty")
}
//先取值,再this.Top--
val = this.arr[this.Top]
this.Top--
return val, nil
} //遍历栈,注意需要从栈顶开始遍历
func (this *Stack) List() {
//先判断栈是否为空
if this.Top == - {
fmt.Println("stack empty")
return
}
fmt.Println("栈的情况如下:")
for i := this.Top; i >= ; i-- {
fmt.Printf("arr[%d]=%d\n", i, this.arr[i])
}
} func main() {
stack := &Stack{
MaxTop : , // 表示最多存放5个数到栈中
Top : -, // 当栈顶为-1,表示栈为空,因为数组下标是从0开始
}
stack.Push()
stack.Push()
stack.Push()
stack.Push()
stack.List()
stack.Pop()
stack.List() }

栈实现综合计算器

package main

import (
"errors"
"fmt"
"strconv"
) //使用数组来模拟一个栈的使用
type Stack struct {
MaxTop int // 表示我们栈最大可以存放数个数
Top int // 表示栈顶, 因为栈顶固定,因此我们直接使用Top
arr []int // 数组模拟栈
} //入栈
func (this *Stack) Push(val int) (err error) { //先判断栈是否满了
if this.Top == this.MaxTop- {
fmt.Println("stack full")
return errors.New("stack full")
}
this.Top++
//放入数据
this.arr[this.Top] = val
return
} //出栈
func (this *Stack) Pop() (val int, err error) {
//判断栈是否空
if this.Top == - {
fmt.Println("stack empty!")
return , errors.New("stack empty")
} //先取值,再 this.Top--
val = this.arr[this.Top]
this.Top--
return val, nil } //遍历栈,注意需要从栈顶开始遍历
func (this *Stack) List() {
//先判断栈是否为空
if this.Top == - {
fmt.Println("stack empty")
return
}
fmt.Println("栈的情况如下:")
for i := this.Top; i >= ; i-- {
fmt.Printf("arr[%d]=%d\n", i, this.arr[i])
} } //判断一个字符是不是一个运算符[+, - , * , /]
func (this *Stack) IsOper(val int) bool { if val == || val == || val == || val == {
return true
} else {
return false
}
} //运算的方法
func (this *Stack) Cal(num1 int, num2 int, oper int) int {
res :=
switch oper {
case :
res = num2 * num1
case :
res = num2 + num1
case :
res = num2 - num1
case :
res = num2 / num1
default:
fmt.Println("运算符错误.")
}
return res
} //编写一个方法,返回某个运算符的优先级[程序员定义]
//[* / => 1 + - => 0]
func (this *Stack) Priority(oper int) int {
res :=
if oper == || oper == {
res =
} else if oper == || oper == {
res =
}
return res
} func main() { //数栈
numStack := &Stack{
MaxTop: ,
Top: -,
}
//符号栈
operStack := &Stack{
MaxTop: ,
Top: -,
} exp := "30+3*6-4-6"
//定义一个index ,帮助扫描exp
index :=
//为了配合运算,我们定义需要的变量
num1 :=
num2 :=
oper :=
result :=
keepNum := "" for {
//这里我们需要增加一个逻辑,
//处理多位数的问题
ch := exp[index : index+] // 字符串. //ch ==>"+" ===> 43
temp := int([]byte(ch)[]) // 就是字符对应的ASCiI码
if operStack.IsOper(temp) { // 说明是符号 //如果operStack 是一个空栈, 直接入栈
if operStack.Top == - { //空栈
operStack.Push(temp)
} else {
//如果发现opertStack栈顶的运算符的优先级大于等于当前准备入栈的运算符的优先级
//,就从符号栈pop出,并从数栈也pop 两个数,进行运算,运算后的结果再重新入栈
//到数栈, 当前符号再入符号栈
if operStack.Priority(operStack.arr[operStack.Top]) >= operStack.Priority(temp) {
num1, _ = numStack.Pop()
num2, _ = numStack.Pop()
oper, _ = operStack.Pop()
//num1先出栈,num2后出栈,说明num2是先入栈的num2作为操作数,num1作为被操作数也就是,num2-num1,num2/num1
result = operStack.Cal(num1, num2, oper)
//将计算结果重新入数栈
numStack.Push(result)
//当前的符号压入符号栈
operStack.Push(temp)
} else {
operStack.Push(temp)
}
}
} else { //说明是数
//处理多位数的思路
//1.定义一个变量 keepNum string, 做拼接
keepNum += ch
//2.每次要向index的后面字符测试一下,看看是不是运算符,然后处理
//如果已经到表达最后,直接将 keepNum
if index == len(exp)- {
val, _ := strconv.ParseInt(keepNum, , )
numStack.Push(int(val))
} else {
//向index 后面测试看看是不是运算符 [index]
if operStack.IsOper(int([]byte(exp[index+ : index+])[])) {
val, _ := strconv.ParseInt(keepNum, , )
numStack.Push(int(val))
keepNum = ""
}
}
} //继续扫描
//先判断index是否已经扫描到计算表达式的最后
if index+ == len(exp) {
break
}
index++ } //如果扫描表达式 完毕,依次从符号栈取出符号,然后从数栈取出两个数,
//运算后的结果,入数栈,直到符号栈为空
for {
if operStack.Top == - {
break //退出条件
}
num1, _ = numStack.Pop()
num2, _ = numStack.Pop()
oper, _ = operStack.Pop()
result = operStack.Cal(num1, num2, oper)
//将计算结果重新入数栈
numStack.Push(result) } //如果我们的算法没有问题,表达式也是正确的,则结果就是numStack最后数
res, _ := numStack.Pop()
fmt.Printf("表达式%s = %v", exp, res)
}

递归

迷宫找路

package main

import (
"fmt"
) //编写一个函数,完成老鼠找路
//myMap *[8][7]int:地图,保证是同一个地图,使用引用
//i,j 表示对地图的哪个点进行测试
func SetWay(myMap *[][]int, i int, j int) bool { //分析出什么情况下,就找到出路
//myMap[6][5] == 2
if myMap[][] == {
return true
} else {
//说明要继续找
if myMap[i][j] == { //如果这个点是可以探测 //假设这个点是可以通, 但是需要探测 上下左右
//换一个策略 下右上左
myMap[i][j] =
if SetWay(myMap, i+, j) { //下
return true
} else if SetWay(myMap, i, j+) { //右
return true
} else if SetWay(myMap, i-, j) { //上
return true
} else if SetWay(myMap, i, j-) { //左
return true
} else { // 死路
myMap[i][j] =
return false
} } else { // 说明这个点不能探测,为1,是强
return false
} }
} func main() {
//先创建一个二维数组,模拟迷宫
//规则
//1. 如果元素的值为1 ,就是墙
//2. 如果元素的值为0, 是没有走过的点
//3. 如果元素的值为2, 是一个通路
//4. 如果元素的值为3, 是走过的点,但是走不通
var myMap [][]int //先把地图的最上和最下设置为1
for i := ; i < ; i++ {
myMap[][i] =
myMap[][i] =
} //先把地图的最左和最右设置为1
for i := ; i < ; i++ {
myMap[i][] =
myMap[i][] =
} myMap[][] =
myMap[][] =
myMap[][] =
myMap[][] = //输出地图
for i := ; i < ; i++ {
for j := ; j < ; j++ {
fmt.Print(myMap[i][j], " ")
}
fmt.Println()
} //使用测试
SetWay(&myMap, , )
fmt.Println("探测完毕....")
//输出地图
for i := ; i < ; i++ {
for j := ; j < ; j++ {
fmt.Print(myMap[i][j], " ")
}
fmt.Println()
} }

哈希表(散列)

雇员系统

package main

import (
"fmt"
"os"
) /*
有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,住址..),当输入该员工
的id时要求查找到该员工的所有信息.
➢要求:
1)不使用数据库尽量节省内存,速度越快越好=>哈希表(散列)
2)添加时,保证按照雇员的id从低到高插入
*/ //定义emp
type Emp struct {
Id int
Name string
Next *Emp
} //方法待定..
func (this *Emp) ShowMe() {
fmt.Printf("链表%d 找到该雇员 %d\n", this.Id%, this.Id)
} //定义EmpLink
//我们这里的EmpLink 不带表头,即第一个结点就存放雇员
type EmpLink struct {
Head *Emp
} //方法待定..
//1. 添加员工的方法, 保证添加时,编号从小到大
func (this *EmpLink) Insert(emp *Emp) { cur := this.Head // 这是辅助指针
var pre *Emp = nil // 这是一个辅助指针 pre 在cur前面
//如果当前的EmpLink就是一个空链表
//为空的话直接放到开头
if cur == nil {
this.Head = emp //完成
return
}
//如果不是一个空链表,给emp找到对应的位置并插入
//思路是 让 cur 和 emp 比较,然后让pre 保持在 cur 前面
for {
if cur != nil {
//比较
if cur.Id > emp.Id {
//找到位置
break
}
//下面两句确保pre在cur前面,且相邻
pre = cur //保证同步
cur = cur.Next //移动,此种方法会导致最后一个判断为nil,对应上面的cur!=nil判断
} else {
break
}
}
//退出时,我们看下是否将emp添加到链表最后
pre.Next = emp //存入pre后面
emp.Next = cur //后面连上cur } //显示链表的信息
func (this *EmpLink) ShowLink(no int) {
if this.Head == nil {
fmt.Printf("链表%d 为空\n", no)
return
} //变量当前的链表,并显示数据
cur := this.Head // 辅助的指针
for {
if cur != nil {
fmt.Printf("链表%d 雇员id=%d 名字=%s ->", no, cur.Id, cur.Name)
cur = cur.Next
} else {
break
}
}
fmt.Println() //换行处理
} //根据id查找对应的雇员,如果没有就返回nil
func (this *EmpLink) FindById(id int) *Emp {
cur := this.Head
for {
//不是最后一个之后,且存在
if cur != nil && cur.Id == id {
return cur
} else if cur == nil { //结束
break
}
//进入下一个
cur = cur.Next
}
return nil
} //定义hashtable ,含有一个链表数组
type HashTable struct {
LinkArr []EmpLink
} //给HashTable 编写Insert 雇员的方法.
func (this *HashTable) Insert(emp *Emp) {
//使用散列函数,确定将该雇员添加到哪个链表
linkNo := this.HashFun(emp.Id)
//使用对应的链表添加
this.LinkArr[linkNo].Insert(emp) //
} //编写方法,显示hashtable的所有雇员
func (this *HashTable) ShowAll() {
for i := ; i < len(this.LinkArr); i++ {
this.LinkArr[i].ShowLink(i)
}
} //编写一个散列方法
func (this *HashTable) HashFun(id int) int {
return id % //得到一个值,就是对于的链表的下标
} //编写一个方法,完成查找
func (this *HashTable) FindById(id int) *Emp {
//使用散列函数,确定将该雇员应该在哪个链表
linkNo := this.HashFun(id)
return this.LinkArr[linkNo].FindById(id)
} func main() { key := ""
id :=
name := ""
var hashtable HashTable
for {
fmt.Println("===============雇员系统菜单============")
fmt.Println("input 表示添加雇员")
fmt.Println("show 表示显示雇员")
fmt.Println("find 表示查找雇员")
fmt.Println("exit 表示退出系统")
fmt.Println("请输入你的选择")
fmt.Scanln(&key)
switch key {
case "input":
fmt.Println("输入雇员id")
fmt.Scanln(&id)
fmt.Println("输入雇员name")
fmt.Scanln(&name)
emp := &Emp{
Id: id,
Name: name,
}
hashtable.Insert(emp)
case "show":
hashtable.ShowAll()
case "find":
fmt.Println("请输入id号:")
fmt.Scanln(&id)
emp := hashtable.FindById(id)
if emp == nil {
fmt.Printf("id=%d 的雇员不存在\n", id)
} else {
//编写一个方法,显示雇员信息
emp.ShowMe()
} case "exit":
os.Exit()
default:
fmt.Println("输入错误")
}
} }

二叉树

前,中,后遍历

package main

import "fmt"

/*
二叉树三种遍历方式
*/ type Hero struct {
No int
Name string
Left *Hero
Right *Hero
} //前序遍历【先输出root结点,然后再输出左子树,然后右子树】
func PreOrder(node *Hero) {
if node != nil {
fmt.Printf("no=%d name=%s\n", node.No, node.Name)
PreOrder(node.Left)
PreOrder(node.Right)
}
} //中序遍历【先输出root左子树,再输出root结点,最后输出root的有子树】
func InfixOrder(node *Hero) {
if node != nil {
InfixOrder(node.Left)
fmt.Printf("no=%d name=%s\n", node.No, node.Name)
InfixOrder(node.Right)
}
} //后序遍历
func PostOrder(node *Hero) {
if node != nil {
PostOrder(node.Left)
PostOrder(node.Right)
fmt.Printf("no=%d name=%s\n", node.No, node.Name)
}
} func main() { //构建一个二叉树
root := &Hero{
No: ,
Name: "宋江",
} left1 := &Hero{
No: ,
Name: "吴用",
} node10 := &Hero{
No: ,
Name: "李逵",
} node12 := &Hero{
No: ,
Name: "杨雄",
}
left1.Left = node10
left1.Right = node12
right1 := &Hero{
No: ,
Name: "卢俊义",
}
root.Left = left1
root.Right = right1
right2 := &Hero{
No: ,
Name: "林冲",
}
right1.Right = right2
fmt.Println("前")
PreOrder(root)
fmt.Println("中")
InfixOrder(root)
fmt.Println("后")
PostOrder(root)
}

。。。

go 算法与数据结构的更多相关文章

  1. 浅谈算法和数据结构: 七 二叉查找树 八 平衡查找树之2-3树 九 平衡查找树之红黑树 十 平衡查找树之B树

    http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html 前文介绍了符号表的两种实现,无序链表和有序数组,无序链表在插入的 ...

  2. python 下的数据结构与算法---2:大O符号与常用算法和数据结构的复杂度速查表

    目录: 一:大O记法 二:各函数高阶比较 三:常用算法和数据结构的复杂度速查表 四:常见的logn是怎么来的 一:大O记法 算法复杂度记法有很多种,其中最常用的就是Big O notation(大O记 ...

  3. LeetCode_算法及数据结构覆盖统计

    [输入]共计151道题的算法&数据结构基础数据 (见附录A) [输出-算法]其中有算法记录的共计 97道 ,统计后 结果如下  top3(递归,动态规划,回溯) 递归 动态规划 回溯 BFS ...

  4. JavaScript算法与数据结构知识点记录

    JavaScript算法与数据结构知识点记录 zhanweifu

  5. Linux内核中的算法和数据结构

    算法和数据结构纷繁复杂,但是对于Linux Kernel开发人员来说重点了解Linux内核中使用到的算法和数据结构很有必要. 在一个国外问答平台stackexchange.com的Theoretica ...

  6. Python算法与数据结构--求所有子数组的和的最大值

    Python算法与数据结构--求所有子数组的和的最大值 玄魂工作室-玄魂 玄魂工作室秘书 玄魂工作室 昨天 题目:输入一个整形数组,数组里有正数也有负数.数组中连续的一个或多个整数组成一个子数组,每个 ...

  7. 【算法与数据结构专场】BitMap算法基本操作代码实现

    上篇我们讲了BitMap是如何对数据进行存储的,没看过的可以看一下[算法与数据结构专场]BitMap算法介绍 这篇我们来讲一下BitMap这个数据结构的代码实现. 回顾下数据的存储原理 一个二进制位对 ...

  8. 算法与数据结构(一) 线性表的顺序存储与链式存储(Swift版)

    温故而知新,在接下来的几篇博客中,将会系统的对数据结构的相关内容进行回顾并总结.数据结构乃编程的基础呢,还是要不时拿出来翻一翻回顾一下.当然数据结构相关博客中我们以Swift语言来实现.因为Swift ...

  9. PHP面试(二):程序设计、框架基础知识、算法与数据结构、高并发解决方案类

    一.程序设计 1.设计功能系统——数据表设计.数据表创建语句.连接数据库的方式.编码能力 二.框架基础知识 1.MVC框架基本原理——原理.常见框架.单一入口的工作原理.模板引擎的理解 2.常见框架的 ...

  10. 使用python解决算法和数据结构--使用栈实现进制转换

    可以将10进制数据转换成2进制,8进制,16进制等. 晚上练练算法和数据结构哈. # coding = utf-8 class Stack: def __init__(self): self.item ...

随机推荐

  1. Ubuntu固定多个静态ip

    步骤: 1.sudo vim /etc/network/interfaces 加入下列内容 auto eth0#此处查看自己的ip信息是eth0还是eth1等等 iface eth0 inet sta ...

  2. ios---运用MJRefresh组件设置下拉刷新

    #import "XMGTopicViewController.h" #import <AFNetworking.h> #import <MJExtension. ...

  3. 对于n!的快速质因数分解

    N!的阶乘的质因数分解 对于N的阶乘 比如8! 我们要算其中一个质因数出现次数 我们注意到 8!=1 2 3 4 5 6 7 8 1 1 1 1 2的倍数出现的次数8/2=4 1 1 4的倍数出现的次 ...

  4. flask使用blinker信号机制解耦业务代码解决ImportError: cannot import name 'app',以异步发送邮件为例

    百度了大半天,不知道怎么搞,直到学习了blinker才想到解决办法,因为之前写java都是文件分开的, 所以发送邮件业务代码也放到view里面,但是异步线程需要使用app,蛋疼的是其他模块不能从app ...

  5. hadoop-2.10.0安装hive-2.3.6

    公司建立数仓,hive是必不可少的,hive是建立在hadoop基础上的数据库,前面已经搭建起了hadoop高可用,要学习hive,先从搭建开始,下面梳理一下hive搭建过程 1.下载hive安装包 ...

  6. mac如何用quick look预览多个文件或者图片

    1.先选中要查看的多个文件,然后点击 空格键 2.按住 command+return 就可以同时预览多个文件了 如果想全屏预览,则在1中,按住 option+空格键 ,然后再进行2 ,就实现全屏预览了 ...

  7. c++中重载运算符

    重载运算符 1,成员函数运算符 运算符重载为类的成员函数一般格式如下 <函数类型> operator <运算符> (参数表) {函数体} 调用成员函数运算符如下 <对象名 ...

  8. 实验21:IPv6

    九.IPv6 1.IPv6(RIP) 实验目的:熟悉IPv6的配置,并经过动态路由协议RIP,使三台路由器相互通讯设备需求:3640三台实验过程: xdbr_R1#sh runipv6 unicast ...

  9. python day01学习

    1.python语言 # 89年 龟叔2.python的特点 # 优点 : 简明 简单 跨平台性好 # 缺点 : 慢 -执行速度相对其他语言慢 # 编程语言的分类:  # 编译型语言: c c++ j ...

  10. ubuntu16.04+Pangolin安装

    学习视觉Slam十四讲到第三章的可视化演示的时候需要Panglolin的使用,因此在Githup上下载了安装包:https://github.com/stevenlovegrove/Pangolin ...