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\n", 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

 隊列

使用數據模擬隊列node

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\t", 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("\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(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\t", tempHead, this.array[tempHead])
        tempHead = (tempHead + 1) % this.maxSize
    }
    fmt.Println()
}

//判斷隊列爲滿
func (this *CircleQueue) IsFull() bool {
    //隊尾以前的長度%總長度=隊首以後的長度
    return (this.tail+1)%this.maxSize == this.head
}

//判斷隊列爲空
func (this *CircleQueue) IsEmpty() bool {
    //當隊列爲空,首尾下標重合
    return this.tail == this.head
}

//取出環形隊列有多少個元素
func (this *CircleQueue) Size() int {
    //這是一個關鍵的算法
    return (this.tail + this.maxSize - this.head) % this.maxSize
}
/*
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("\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(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("\n逆序打印")
    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]->\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:   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 出圈\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(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\n", 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\n", insertIndex, arr[insertIndex], insertVal)
            arr[insertIndex+1] = arr[insertIndex] //數據後移
            insertIndex--
        }
        //插入
        if insertIndex+1 != i {
            fmt.Printf("insertIndex=%v\n", insertIndex)
            arr[insertIndex+1] = insertVal
        }
        fmt.Printf("第%d次插入後 %v\n", 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

 

使用數組來模擬一個棧的使用app

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\n", 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

棧實現綜合計算器ide

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\n", 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\n", 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 爲空\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 [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 的僱員不存在\n", 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\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:   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

 

。。。

相關文章
相關標籤/搜索