常见算法

1、冒泡排序

    // 冒泡排序
    a := []uint8{9, 20, 10, 23, 7, 22, 88, 102}
    for i := 0; i < len(a); i++ {
        for k := i + 1; k < (len(a) - i); k++ {
            if a[i] > a[k] {
                a[i], a[k] = a[k], a[i]
            }
        }
    }
    fmt.Println(a)
冒泡排序

2、选择排序

    // 选择排序
    a := []int8{9, 20, -1, 10, -5, 23, 7, 22, 88, 102}
    for i := 0; i < len(a); i++ {
        var (
            min_n int8 = a[i]
            min_i int  = i
        )
        for k := i + 1; k < len(a); k++ {
            if a[k] < min_n {
                min_n = a[k]
                min_i = k
            }
        }
        a[i], a[min_i] = a[min_i], a[i]
    }
    fmt.Println(a)
选择排序

 3、插入排序

    a := []int8{9, 20, 22, -1, 10, -5, 23, 7, 7, 22, 88, 102}
    for i := 1; i < len(a); i++ {
        for k := i - 1; k >= 0; k-- {
            if a[k+1] < a[k] {
                a[k+1], a[k] = a[k], a[k+1]
            }
        }
    }
    fmt.Println(a)
插入排序

 4、随机数出现的概率为平方

正常来讲,对于[0-10)范围内的任意一个整除的随机数概率为0.1,如果我要实现其中任意一个整数的随机数为0.1^2呢?

 下面的示例中,是计算随机数为0-4范围的平方,正常来讲,0-4范围是5个,所以出现的概率为1/2。求其平方,即0.25

    // 随机数的概率为平方
    var count float64 = 0
    for i := 0; i < 100000; i++ {
        if rand.Intn(10) < 5 {
            if rand.Intn(10) < 5 {
                count++
            }
        }
    }
    p := count / 100000
    fmt.Println(p)
随机数平方概率

 5、这是一个题目:

我当前有一个函数可以等概率随机返回[1-5]之间的任意一个数,在不使用内部函数的前提下,如何只根据当前的这个随机函数来等概率返回[1-7]中的任意一个数呢?

下面是这个随机函数:

func f1() int {
    rn := rand.Intn(5) + 1
    return rn
}

解题思路是这样的,可以先构造一个函数,等概率返回0和1,然后再构造一个函数,1-7中的数,可以用三个bit位来表示了,但是还有返回0的时候,当返回0的时候,扔掉,重新来随机

下面是等概率返回0和1的函数:

func f2() int {
    for {
        num_1 := f1()
        if num_1 < 3 {
            return 0
        } else if num_1 == 3 {
            continue
        } else {
            return 1
        }
    }
}
f2

下面是返回[1-7]的函数:

func f3() int {
    for {
        num_2 := (f2() << 2) + (f2() << 1) + f2()
        if num_2 == 0 {
            continue
        } else {
            return num_2
        }
    }
}
f3()

 问题来了:

上面我已经用go语言写出了冒泡排序、选择排序和插入排序,我如何验证我所写的代码是否正确呢?当数据量小的时候,我们可以用肉眼去观察,但是这并不代表就是正确的逻辑,当数据量很大的时候呢?其实,在上面的代码中,我对冒泡排序和选择排序的逻辑是有问题的,是错误的;我们如何验证呢?这时候我们需要用到的就是对数器,通过对数器我们就可以不断的去验证我的代码,数据量大小也是可控的。

下面是我编写的对数器及各个排序的函数,其中三个排序函数是经过验证而改正的:

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    // 对数器,生成随机样本,自己做比对的机器,通过对数器,可以调出所有错误来
    var (
        lenth     int = 10
        maxValue  int = 1000
        testTimes int = 10
    )
    for i := 0; i < testTimes; i++ {
        src_sli := rlrv(lenth, maxValue)
        sort_sli := insertSort(src_sli)
        // sort_sli := bubbleSort(src_sli)
        // sort_sli := chooseSort(src_sli)
        if !isSorted(sort_sli) {
            fmt.Println("Sort is false") // 这里如果排序不正确,则返回false
        }
    }

}

// 选择排序
func chooseSort(sli []int) []int {
    for i := 0; i < len(sli)-1; i++ {
        var (
            min_n int = sli[i]
            min_i int = i
        )
        for k := i + 1; k < len(sli); k++ {
            if sli[k] < min_n {
                min_n = sli[k]
                min_i = k
            }
        }
        sli[i], sli[min_i] = sli[min_i], sli[i]
    }
    return sli
}

// 插入排序
func insertSort(sli []int) []int {
    for i := 1; i < len(sli); i++ {
        for k := i - 1; k >= 0; k-- {
            if sli[k+1] < sli[k] {
                sli[k+1], sli[k] = sli[k], sli[k+1]
            }
        }
    }
    return sli
}

// 冒泡排序
func bubbleSort(sli []int) []int {
    for i := 1; i < len(sli); i++ {
        for k := 1; k < len(sli); k++ {
            if sli[k-1] > sli[k] {
                sli[k-1], sli[k] = sli[k], sli[k-1]
            }
        }
    }
    return sli
}

// 是否已排序
func isSorted(sli []int) bool {
    if len(sli) == 0 {
        return true
    }
    for i := 0; i < len(sli)-1; i++ {
        if sli[i] > sli[i+1] {
            return false
        }
    }
    return true
}

// 此处暂未使用,后面会用
func copySli(sli []int) []int {
    newSli := make([]int, len(sli))
    copy(newSli, sli)
    return newSli
}

// 生成一个随机切片
func rlrv(lenghth int, value int) []int {
    sli := make([]int, lenghth)
    for i := 0; i < len(sli); i++ {
        sli[i] = rand.Intn(value) + 1
    }
    return sli
}

对数器
对数器

 对于上面代码还是可以继续优化的,根据自己需求添加不同功能,比如我想知道排序函数用时多久,可以添加startTime和endTime,然后相减。通过查看时间可以了解到,对于上面三个排序函数,其中选择排序相比用时较短

sort包

 Go的标准库提供了sort库,用来给线性数据结构排序、二分查找。

a := []int{-1, 23, 5, 9, 7}
// sort.Sort(sort.IntSlice(a)) // sort.IntSlice(a)强制类型转换以施加接口方法
sort.Ints(a)   // 就地修改原切片的底层数组
fmt.Println(a) // 默认升序
b := []string{"xyz", "a", "abc", "Ab", "X"}
sort.Strings(b)
fmt.Println(b)
// 降序
sort.Sort(sort.Reverse(sort.IntSlice(a)))
fmt.Println(a)
// 二分查找
a := []int{-1, 23, 5, 9, 7}
sort.Ints(a)
// 二分查找,必须是升序
// 二分查找的前提是 有序
i := sort.SearchInts(a, 7)
fmt.Println(i)

 

posted on 2023-06-14 19:35  自然洒脱  阅读(65)  评论(0编辑  收藏  举报