zoukankan      html  css  js  c++  java
  • go 算法与数据结构

    数据结构

    稀疏数组

    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()
    }
    View Code

     队列

    使用数据模拟队列

    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)
            }
        }
    
    
    }
    View Code

    通过数组实现环形队列

    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("输入错误")
            }
        }
    }
    View Code

    链表

    单向链表

    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)
    }
    View Code

    双向链表

    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)
    
    }
    View Code

     环形单向链表

    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)
    
    }
    View Code

    环形单向链表应用

    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)
    
    }
    View Code

    算法

    排序

    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)
    }
    View Code

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

    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()
    
    }
    View Code

    栈实现综合计算器

    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)
    }
    View Code

    递归

     迷宫找路

    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()
        }
    
    }
    View Code

     哈希表(散列)

     雇员系统

    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("输入错误")
            }
        }
    
    }
    View Code

     二叉树

     前,中,后遍历

    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)
    }
    View Code

    。。。

  • 相关阅读:
    函数的定义
    函数加载的过程
    js中的return
    快速排序
    冒泡排序
    数组的案例
    正睿暑期培训day3考试
    bzoj2115 Xor
    luogu4570 元素
    bzoj4827 Hnoi2017 礼物
  • 原文地址:https://www.cnblogs.com/huay/p/12204573.html
Copyright © 2011-2022 走看看