golang 各种排序大比拼

1、准备工作

准备数据:
生成随机数并写入文件,之后在把数据读取出来

//新生成整数随机数,并存储在txt文件中,
func NewIntRandm(fileName string, number, maxrandm int) {
    filename := fileName
    file, err := os.Create(filename)

    if err != nil {
        return
    }
    r := rand.New(rand.NewSource(time.Now().UnixNano()))
    rans := make([]string, 0, number)
    for i := 0; i < number; i++ {
        rans = append(rans, strconv.Itoa(r.Intn(maxrandm)))
    }
    file.WriteString(strings.Join(rans, " "))
    defer file.Close()
}

//把一串数组存入文件总
func SavaRandmInt(fileName string, data []int) {
    if fileName == " " || len(data) == 0 {
        return
    }
    var file *os.File
    var openerr error
    file, openerr = os.Open(fileName)
    if openerr != nil {
        var newerr error
        file, newerr = os.Create(fileName)
        if newerr != nil {
            return
        }
    }

    rans := make([]string, 0, len(data))
    for _, v := range data {
        rans = append(rans, strconv.Itoa(v))
    }
    file.WriteString(strings.Join(rans, " "))
    defer file.Close()
}

准备计时的程序:

package util

import "time"

type Stopwatch struct {
    start time.Time
    stop  time.Time
}

func (s *Stopwatch) Start() {
    s.start = time.Now()
}

func (s *Stopwatch) Stop() {
    s.stop = time.Now()
}

//纳秒
func (s Stopwatch) RuntimeNs() int {

    return s.stop.Nanosecond() - s.start.Nanosecond()
}

//微妙
func (s Stopwatch) RuntimeUs() float64 {
    return (float64)(s.stop.Nanosecond()-s.start.Nanosecond()) / 1000.00
}

//毫秒
func (s Stopwatch) RuntimeMs() float64 {
    return (float64)(s.stop.Nanosecond()-s.start.Nanosecond()) / 1000000.00
}

//秒
func (s Stopwatch) RuntimeS() float64 {
    return (float64)(s.stop.Nanosecond()-s.start.Nanosecond()) / 10000000000.00
}

2、开始写排序

我模仿golang中的sort源码包中的写法,暴露了一个接口,把排序的实现都写在内部

package sort

// package main

type Interface interface {
    //获取数据的长度
    Len() int
    //判读索引为i和索引为j的值的大小,在实现的时候如果判断i>j 返回true,则为升序,反之为降序
    Less(i, j int) bool
    //交换索引i,j的值
    Swap(i, j int)
}

//冒泡排序
func BubbleSort(data Interface) {
    n := data.Len()
    for index := 0; index < n; index++ {
        for j := index + 1; j < n; j++ {
            if data.Less(index, j) {
                data.Swap(index, j)
            }
        }
    }
}

//此方法比上面的冒泡算法快,因为我找最小元素是指记住下标,并没有每一次都做元素交换
func SelectSort(data Interface) {
    n := data.Len()
    var min int
    for index := 0; index < n; index++ {
        min = index
        for j := index + 1; j < n; j++ {
            if data.Less(min, j) {
                min = j
            }
        }
        data.Swap(index, min)
    }
}

//插入排序
func InsertSrot(data Interface) {
    count := data.Len()
    for index := 1; index < count; index++ {
        for j := index; j > 0 && data.Less(j, j-1); j-- { //j>0 做一个边界守护,不让下标小于0
            data.Swap(j, j-1)
        }
    }
}

//希尔排序
func ShellSort(data Interface) {
    N := data.Len()
    h := 1
    for h < N/3 {
        h = 3*h + 1
    }
    for h > 0 {
        for index := h; index < N; index++ {
            for j := index; j >= h && data.Less(j, j-h); j -= h { //j>0 做一个边界守护,不让下标小于0
                data.Swap(j, j-h)
            }
        }
        h = h / 3
    }
}

//快速排序
func QuickSort(data Interface) {
    n := data.Len()
    low, row := 0, n-1
    quickSort(data, low, row)
}

func quickSort(data Interface, low, row int) {
    if low < row {
        i, j, x, last := low, row, low, 0 //0就是使用第一个作为基准值,last这个变量时为了基准最后一次交换变量时出现在那次
        for i < j {
            for i < j && data.Less(x, j) { //比x小的放在前面出现的坑中
                j--
            }
            if i < j {
                data.Swap(i, j)
                i++
                x = j
                last = 1
            }
            for i < j && data.Less(i, x) { //比x大的放在后面出现的坑中
                i++
            }
            if i < j {
                data.Swap(i, j)
                j--
                x = i
                last = -1
            }
        }
        if last == 1 {
            data.Swap(j, x)
        } else if last == -1 {
            data.Swap(i, x)
        }
        quickSort(data, low, i-1)
        quickSort(data, i+1, row)
    }
}

//通过控制Less方法来控制升序降序
func HeapSort(data Interface) {
    makeHeap(data)
    n := data.Len()
    for i := n - 1; i >= 1; i-- {
        data.Swap(0, i)
        heapFixdown(data, 0, i)
    }
}

func makeHeap(data Interface) {
    n := data.Len()
    for i := (n - 1) >> 1; i >= 0; i-- {
        heapFixdown(data, i, n)
    }
}
func heapFixdown(data Interface, r, n int) {
    root := r //跟结点
    for {
        leftChildIndex := root<<1 + 1
        if leftChildIndex >= n {
            break
        }
        if leftChildIndex+1 < n && data.Less(leftChildIndex+1, leftChildIndex) {
            leftChildIndex++
        }
        if data.Less(root, leftChildIndex) {
            return
        }
        data.Swap(leftChildIndex, root)
        root = leftChildIndex
    }
}

3、开始使用

//先实现这个排序接口
type InSort []int
func (is InSort) Len() int {
    return len(is)
}//降序
func (is InSort) Less(i, j int) bool {
    return is[i] > is[j]
}
func (is InSort) Swap(i, j int) {
    is[i], is[j] = is[j], is[i]
}

func main() {
    fileName := "randm.txt"
    // util.NewIntRandm(fileName, 1000000, 10000) //封装生成5000000个随机数字
    fileUtil := util.FileUtil{}
    insort := InSort{}
    insort = fileUtil.ReaderAllInt(fileName) //读取生成的随机数
    fmt.Println(insort.Len())
    t := new(util.Stopwatch) //封装的计时间的方法
    t.Start()
    // sort.HeapSort(insort) //开始排序,519.8732 ms
    sort.QuickSort(insort) //开始排序,7.0267 ms
    t.Stop()
    fmt.Println(t.RuntimeMs(), "ms")
    util.SavaRandmInt("result.txt", insort)
}
快排:10000数组 7.0267 ms,1000000数组 37.7612 ms
堆排序:10000数组 10.0039 ms,1000000数组  358.6429 ms

下面是我测试的一些数据:

     HeapSort(insort) //堆排序 10000个数 4.0013 ms,100000个数 54.0659 ms,很稳定,500000个数 208.1511 ms 很稳定
    sort.QuickSort(insort, 0, len(insort)-1) //快速排序   10000个数 3.0017 ms,100000个数,33.0222 ms,很稳定,500000个数 150.1096 ms  很稳定,100000个数 94.0823 ms 很稳定
    sort.SelectSort(insort) //选择排序 10000个数   130.8017 ms,100000个数 时间很长
    sort.BubbleSort(insort) //冒泡排序  10000个数 203.5344ms ,100000个数 187.7438 ms
    sort.InsertSrot(insort) // 插入排序   10000个数 858.6085 ms,100000个数,时间很长
    sort.ShellSort(insort) //希尔插入   10000个数  10.9876 ms,100000个数  46.0322 m  ,就做这个范围,很稳定,500000个数 141.8833 ms,相对稳定
    sort.Sort(insort) //golang源码的排序 10000个数 6.0062 ms  ,100000个数 19.9988 ms~89.0574 ms  不稳定,500000个数 358.2536 ms 稳定
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值