数据结构
稀疏数组
package main import "fmt" /* 稀疏数组 案例:五子棋存盘与复盘 节省存储空间 */ type ValNode struct { row int //行 col int //列 val int //值 } //原始数组实现 func normalArray() { var chessMap [11][11]int chessMap[1][2] = 1 //黑子 chessMap[2][3] = 2 //白子 //输出 for _, v := range chessMap { for _, v2 := range v { fmt.Printf("%d ", v2) } fmt.Println() } } //稀疏数组实现 func sparseArray() { //数据源 var chessMap [11][11]int chessMap[1][2] = 1 //黑子 chessMap[2][3] = 2 //白子 //切片 var sparseArr []ValNode //创建一个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{ row: i, col: j, val: v2, } sparseArr = append(sparseArr, valNode) } } } //输出稀疏数组 fmt.Println("当前的稀疏数组是。。。") //循环切片 for i, valNode := range sparseArr { fmt.Printf("%d:%d %d %d ", i, valNode.row, valNode.col, valNode.val) } var chessMap2 [11][11]int //稀疏数组恢复原始数组 for i, valNode := range sparseArr { //跳过第一行默认记录值 if i != 0 { 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 [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") } //元素从下标为1开始存入 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() { fmt.Println("队列当前的情况是:") //this.front//不包含队首 for i := this.front + 1; i <= this.rear; i++ { fmt.Printf("array[%d]=%d ", i, this.array[i]) } } func main(){ //创建一个队列 queue:=&Queue{ maxSize: 5, array: [5]int{}, 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.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(0) } } }
通过数组实现环形队列
package main import ( "errors" "fmt" "os" ) //数组模拟环形队列 /* 1.尾索引下一个为头索引时表示队列满,即将队列容量空出一个作为约定,这个在做判断队列满的时候需要注意 (tail+1)%maxSize==head满 2.tail==head [空] */ type CircleQueue struct { maxSize int //4 array [5]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 + 1) % this.maxSize 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 return } //显示队列 func (this *CircleQueue) ListQueue() { fmt.Println("环形队列情况如下") //取出当前队列有多少个元素 size := this.Size() if size == 0 { fmt.Println("队列为空") } //设计一个辅助便理那个指向head tempHead := this.head for i := 0; i < size; i++ { fmt.Printf("arr[%d]=%d ", 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 } /* 1.队尾在队首之后 this.tail% this.maxSize + this.maxSize% this.maxSize - this.head% this.maxSize 队尾之前的长度+1-队首之前的长度=总长度 */ func main() { cq := CircleQueue{ maxSize: 5, array: [5]int{}, 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 := 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(0) 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: 1, name: "宋江", nickname: "及时雨", } hero2 := &HeroNode{ no: 2, name: "卢俊义", nickname: "玉麒麟", } hero3 := &HeroNode{ no: 3, name: "林冲", nickname: "豹子头", } hero4 := &HeroNode{ no: 3, 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: 1, name: "宋江", nickname: "及时雨", } hero2 := &HeroNode{ no: 2, name: "卢俊义", nickname: "玉麒麟", } hero3 := &HeroNode{ no: 3, name: "林冲", nickname: "豹子头", } hero4 := &HeroNode{ no: 3, name: "吴用", nickname: "智多星", } InsertHeroNode(head, hero1) InsertHeroNode(head, hero2) InsertHeroNode(head, hero3) InsertHeroNode(head, hero4) ListHeroNode(head) fmt.Println(" 逆序打印") 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]-> ", 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 ", 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 ", id) flag = false break } //继续循环,类似i++,两个结点同步循环 temp = temp.next //移动 helper = helper.next //移动 } //flag为true表示没找到 if flag { fmt.Printf("对不起,没有no=%d ", id) } return head } func main() { //初始化一个环形链表的头节点 head := &CatNode{} //创建一只猫 cat1 := &CatNode{ no: 1, name: "tom", } cat2 := &CatNode{ no: 2, name: "tom2", } cat3 := &CatNode{ no: 3, name: "tom3", } cat4 := &CatNode{ no: 4, name: "tom4", } InsertCatNode(head, cat1) InsertCatNode(head, cat2) InsertCatNode(head, cat3) InsertCatNode(head, cat4) ListCircleLink(head) head = DelCatNode(head, 1) 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 < 1 { fmt.Println("num的值不对") return first } //循环的构建这个环形链表 for i := 1; i <= num; i++ { boy := &Boy{ No: i, } //分析构成循环链表,需要一个辅助指针 //1.因为第一个小孩比较特殊 if i == 1 { //第一个小孩 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 := 1; i <= startNo-1; i++ { first = first.Next tail = tail.Next } //保持顺序推进到开始结点 fmt.Println() //.开始数countNum,然后删除first指向的小孩 for { //开始数countNum-1次 for i := 1; i <= countNum-1; i++ { first = first.Next tail = tail.Next } fmt.Printf("小孩编号为%d 出圈 ", first.No) //删除first执行大小孩 first = first.Next //链接后面的新的,同时表示删除 //tail始终是first前面一个 tail.Next = first //把first前面的链接上 //判断如果tail==first,圈子中只有一个小孩 if tail == first { break } } fmt.Printf("小孩编号为%d出圈 ", first.No) } func main() { first := AddBoy(5) //显示 ShowBoy(first) PlayGame(first, 2, 3) }
算法
排序
package main import ( "fmt" ) /* 选择排序 */ func SelectSort(arr *[6]int) { for j := 0; j < len(arr)-1; j++ { max := arr[j] maxIndex := j //每一次都找到全局最大值,放到前面 for i := j + 1; 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 ", j+1, *arr) } } /* 插入排序 */ func InsertSort(arr *[7]int) { //完成第一次,给第二个元素找到合适的位置并插入 for i := 1; i < len(arr); i++ { insertVal := arr[i] insertIndex := i - 1 //下标 //如果后面的值大于前面的值,进行交换 //对i前面的数,从右向左,一次相邻作比较,大的放前面,同时数据后移 for insertIndex >= 0 && arr[insertIndex] < insertVal { fmt.Printf("arr[%v]=%v<%v ", insertIndex, arr[insertIndex], insertVal) arr[insertIndex+1] = arr[insertIndex] //数据后移 insertIndex-- } //插入 if insertIndex+1 != i { fmt.Printf("insertIndex=%v ", insertIndex) arr[insertIndex+1] = insertVal } fmt.Printf("第%d次插入后 %v ", i, *arr) } } /* 快速排序法 */ //说明 //1.left表示数组左边的下标 //2.right表示数组右边的下标 //3.array表示要排序的数组 func QuickSort(left int, right int, array *[9]int) { l := left r := right //pivot是中轴,支点 pivot := array[(left+right)/2] temp := 0 //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:=[9]int{-9,78,0,23,-567,70,123,90,-23} fmt.Println("初始",arr) //调用快速排序 QuickSort(0,len(arr)-1,&arr) fmt.Println("main..") fmt.Println(arr) }
栈
使用数组来模拟一个栈的使用
package main import ( "errors" "fmt" ) //使用数组来模拟一个栈的使用 type Stack struct { MaxTop int //表示我们栈最大可以存放的个数 Top int //表示栈顶,因为栈顶固定,因此直接使用Top arr [5]int //数组模拟战 } //入栈 func (this *Stack) Push(val int) (err error) { //判断栈是否满了 if this.Top == this.MaxTop-1 { 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 == -1 { fmt.Println("stack empty !") return 0, errors.New("stack empty") } //先取值,再this.Top-- val = this.arr[this.Top] this.Top-- return val, nil } //遍历栈,注意需要从栈顶开始遍历 func (this *Stack) List() { //先判断栈是否为空 if this.Top == -1 { fmt.Println("stack empty") return } fmt.Println("栈的情况如下:") for i := this.Top; i >= 0; i-- { fmt.Printf("arr[%d]=%d ", i, this.arr[i]) } } func main() { stack := &Stack{ MaxTop : 5, // 表示最多存放5个数到栈中 Top : -1, // 当栈顶为-1,表示栈为空,因为数组下标是从0开始 } stack.Push(2) stack.Push(3) stack.Push(4) stack.Push(5) stack.List() stack.Pop() stack.List() }
栈实现综合计算器
package main import ( "errors" "fmt" "strconv" ) //使用数组来模拟一个栈的使用 type Stack struct { MaxTop int // 表示我们栈最大可以存放数个数 Top int // 表示栈顶, 因为栈顶固定,因此我们直接使用Top arr [20]int // 数组模拟栈 } //入栈 func (this *Stack) Push(val int) (err error) { //先判断栈是否满了 if this.Top == this.MaxTop-1 { 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 == -1 { fmt.Println("stack empty!") return 0, errors.New("stack empty") } //先取值,再 this.Top-- val = this.arr[this.Top] this.Top-- return val, nil } //遍历栈,注意需要从栈顶开始遍历 func (this *Stack) List() { //先判断栈是否为空 if this.Top == -1 { fmt.Println("stack empty") return } fmt.Println("栈的情况如下:") for i := this.Top; i >= 0; i-- { fmt.Printf("arr[%d]=%d ", i, this.arr[i]) } } //判断一个字符是不是一个运算符[+, - , * , /] func (this *Stack) IsOper(val int) bool { if val == 42 || val == 43 || val == 45 || val == 47 { return true } else { return false } } //运算的方法 func (this *Stack) Cal(num1 int, num2 int, oper int) int { res := 0 switch oper { case 42: res = num2 * num1 case 43: res = num2 + num1 case 45: res = num2 - num1 case 47: res = num2 / num1 default: fmt.Println("运算符错误.") } return res } //编写一个方法,返回某个运算符的优先级[程序员定义] //[* / => 1 + - => 0] func (this *Stack) Priority(oper int) int { res := 0 if oper == 42 || oper == 47 { res = 1 } else if oper == 43 || oper == 45 { res = 0 } return res } func main() { //数栈 numStack := &Stack{ MaxTop: 20, Top: -1, } //符号栈 operStack := &Stack{ MaxTop: 20, Top: -1, } exp := "30+3*6-4-6" //定义一个index ,帮助扫描exp index := 0 //为了配合运算,我们定义需要的变量 num1 := 0 num2 := 0 oper := 0 result := 0 keepNum := "" for { //这里我们需要增加一个逻辑, //处理多位数的问题 ch := exp[index : index+1] // 字符串. //ch ==>"+" ===> 43 temp := int([]byte(ch)[0]) // 就是字符对应的ASCiI码 if operStack.IsOper(temp) { // 说明是符号 //如果operStack 是一个空栈, 直接入栈 if operStack.Top == -1 { //空栈 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)-1 { val, _ := strconv.ParseInt(keepNum, 10, 64) numStack.Push(int(val)) } else { //向index 后面测试看看是不是运算符 [index] if operStack.IsOper(int([]byte(exp[index+1 : index+2])[0])) { val, _ := strconv.ParseInt(keepNum, 10, 64) numStack.Push(int(val)) keepNum = "" } } } //继续扫描 //先判断index是否已经扫描到计算表达式的最后 if index+1 == len(exp) { break } index++ } //如果扫描表达式 完毕,依次从符号栈取出符号,然后从数栈取出两个数, //运算后的结果,入数栈,直到符号栈为空 for { if operStack.Top == -1 { 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 *[8][7]int, i int, j int) bool { //分析出什么情况下,就找到出路 //myMap[6][5] == 2 if myMap[6][5] == 2 { return true } else { //说明要继续找 if myMap[i][j] == 0 { //如果这个点是可以探测 //假设这个点是可以通, 但是需要探测 上下左右 //换一个策略 下右上左 myMap[i][j] = 2 if SetWay(myMap, i+1, j) { //下 return true } else if SetWay(myMap, i, j+1) { //右 return true } else if SetWay(myMap, i-1, j) { //上 return true } else if SetWay(myMap, i, j-1) { //左 return true } else { // 死路 myMap[i][j] = 3 return false } } else { // 说明这个点不能探测,为1,是强 return false } } } func main() { //先创建一个二维数组,模拟迷宫 //规则 //1. 如果元素的值为1 ,就是墙 //2. 如果元素的值为0, 是没有走过的点 //3. 如果元素的值为2, 是一个通路 //4. 如果元素的值为3, 是走过的点,但是走不通 var myMap [8][7]int //先把地图的最上和最下设置为1 for i := 0; i < 7; i++ { myMap[0][i] = 1 myMap[7][i] = 1 } //先把地图的最左和最右设置为1 for i := 0; i < 8; i++ { myMap[i][0] = 1 myMap[i][6] = 1 } myMap[3][1] = 1 myMap[3][2] = 1 myMap[1][2] = 1 myMap[2][2] = 1 //输出地图 for i := 0; i < 8; i++ { for j := 0; j < 7; j++ { fmt.Print(myMap[i][j], " ") } fmt.Println() } //使用测试 SetWay(&myMap, 1, 1) fmt.Println("探测完毕....") //输出地图 for i := 0; i < 8; i++ { for j := 0; j < 7; 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 ", this.Id%7, 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 为空 ", 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 [7]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 := 0; i < len(this.LinkArr); i++ { this.LinkArr[i].ShowLink(i) } } //编写一个散列方法 func (this *HashTable) HashFun(id int) int { return id % 7 //得到一个值,就是对于的链表的下标 } //编写一个方法,完成查找 func (this *HashTable) FindById(id int) *Emp { //使用散列函数,确定将该雇员应该在哪个链表 linkNo := this.HashFun(id) return this.LinkArr[linkNo].FindById(id) } func main() { key := "" id := 0 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 的雇员不存在 ", id) } else { //编写一个方法,显示雇员信息 emp.ShowMe() } case "exit": os.Exit(0) 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 ", 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 ", 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 ", node.No, node.Name) } } func main() { //构建一个二叉树 root := &Hero{ No: 1, Name: "宋江", } left1 := &Hero{ No: 2, Name: "吴用", } node10 := &Hero{ No: 10, Name: "李逵", } node12 := &Hero{ No: 12, Name: "杨雄", } left1.Left = node10 left1.Right = node12 right1 := &Hero{ No: 3, Name: "卢俊义", } root.Left = left1 root.Right = right1 right2 := &Hero{ No: 4, Name: "林冲", } right1.Right = right2 fmt.Println("前") PreOrder(root) fmt.Println("中") InfixOrder(root) fmt.Println("后") PostOrder(root) }
。。。