准备数据:
生成随机数并写入文件,之后在把数据读取出来
//新生成整数随机数,并存储在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
}
我模仿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
}
}
//先实现这个排序接口
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 稳定