幾種常用的排序程式碼

janbar發表於2020-10-18

簡單的程式碼

    在我的筆記裡面找到幾種常用的排序程式碼,包括“氣泡排序、選擇排序、二分排序、快速排序”。關於這些排序的原理,我之前是有專門研究的,網上也有很多教程。

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	rand.Seed(time.Now().Unix())

	s := randInt(20)
	BubblingSort(s, len(s))
	fmt.Println(s)

	s = randInt(20)
	SelectSort(s, len(s))
	fmt.Println(s)

	s = randInt(20)
	BisectionSort(s, len(s))
	fmt.Println(s)

	s = randInt(20)
	quickSort(s, 0, len(s)-1)
	fmt.Println(s)
}

func randInt(n int) []int {
	res := make([]int, n)
	for i := 0; i < n; i++ {
		res[i] = rand.Intn(100)
	}
	return res
}

func BubblingSort(nums []int, ln int) {
	for i := 0; i < ln-1; i++ {
		flag := true
		for j := 0; j < ln-i-1; j++ {
			if nums[j] > nums[j+1] {
				nums[j], nums[j+1] = nums[j+1], nums[j]
				flag = false
			}
		}
		if flag {
			break // 已經有序,不用繼續
		}
	}
}

func SelectSort(nums []int, ln int) {
	for i := 0; i < ln; i++ {
		min := i
		for j := i + 1; j < ln; j++ {
			if nums[min] > nums[j] {
				min = j
			}
		}
		nums[i], nums[min] = nums[min], nums[i]
	}
}

func BisectionSort(nums []int, ln int) {
	for i := 1; i < ln; i++ {
		tmp := nums[i]
		low, mid, high := 0, -1, i-1
		for low <= high {
			mid = (low + high) / 2
			if tmp < nums[mid] {
				high = mid - 1
			} else {
				low = mid + 1
			}
		}
		for j := i - 1; j >= low; j-- {
			nums[j+1] = nums[j]
		}
		if low != i {
			nums[low] = tmp
		}
	}
}

func quickSort(num []int, low, high int) {
	s, e, k := low, high, num[low]
	for e > s {
		for e > s && num[e] >= k {
			e--
		}
		if num[e] <= k {
			num[s], num[e] = num[e], num[s]
		}
		for e > s && num[s] <= k {
			s++
		}
		if num[s] >= k {
			num[s], num[e] = num[e], num[s]
		}
		if s > low {
			quickSort(num, low, s-1)
		}
		if e < high {
			quickSort(num, e+1, high)
		}
	}
}

使用go自帶的排序

對[]int型別排序

package main

import (
	"fmt"
	"math/rand"
	"sort"
	"time"
)

func main() {
	rand.Seed(time.Now().Unix())

	s := randInt(20)
	sort.Ints(s)
	fmt.Println(s)
}

func randInt(n int) []int {
	res := make([]int, n)
	for i := 0; i < n; i++ {
		res[i] = rand.Intn(100)
	}
	return res
}

對[]float64型別排序

package main

import (
	"fmt"
	"math/rand"
	"sort"
	"time"
)

func main() {
	rand.Seed(time.Now().Unix())

	s := randFloat64(20)
	sort.Float64s(s)
	fmt.Println(s)

}

func randFloat64(n int) []float64 {
	res := make([]float64, n)
	for i := 0; i < n; i++ {
		res[i] = rand.Float64()
	}
	return res
}

對[]string型別排序

package main

import (
	"encoding/base64"
	"fmt"
	"math/rand"
	"sort"
	"time"
)

func main() {
	rand.Seed(time.Now().Unix())

	s := randString(20)
	sort.Strings(s)
	fmt.Println(s)

}

func randString(n int) []string {
	res := make([]string, n)
	tmp := make([]byte, 10)
	for i := 0; i < n; i++ {
		rand.Read(tmp)
		res[i] = base64.StdEncoding.EncodeToString(tmp)
	}
	return res
}

自定義型別排序

    對於自定義型別,需要實現LessSwapLen這三個sort包的介面,然後直接使用sort.Sort方法就可以了。

package main

import (
	"encoding/base64"
	"fmt"
	"math/rand"
	"sort"
)

func main() {
	peoples := SortPeople{
		{
			name: "張三",
			age:  25,
		}, {
			name: "李四",
			age:  18,
		}, {
			name: "王五",
			age:  20,
		},
	}
	sort.Sort(peoples)
	fmt.Println(peoples)

}

type (
	people struct {
		name string
		age  int
	}
	SortPeople []people
)

func (d SortPeople) Less(i, j int) bool {
	return d[i].age < d[j].age
}

func (d SortPeople) Swap(i, j int) {
	d[i], d[j] = d[j], d[i]
}

func (d SortPeople) Len() int {
	return len(d)
}

便攜的用法sort.Slice

    直接使用sort.Slice只需要定義less func(i, j int) bool方法就可以完成排序,程式碼是通過快速排序完成,不過具體實現加了反射,效能稍微有影響。

package main

import (
	"encoding/base64"
	"fmt"
	"math/rand"
	"sort"
)

func main() {
	peoples := []people{
		{
			name: "張三",
			age:  25,
		}, {
			name: "李四",
			age:  18,
		}, {
			name: "王五",
			age:  20,
		},
	}
	sort.Slice(peoples, func(i, j int) bool {
		return peoples[i].age < peoples[j].age
	})
	fmt.Println(peoples)

}

便攜的用法sort.SliceStable

    該方法類似上一個方法,我看具體實現是使用一個穩定的排序演算法。

package main

import (
	"encoding/base64"
	"fmt"
	"math/rand"
	"sort"
)

func main() {
	peoples := []people{
		{
			name: "張三",
			age:  25,
		}, {
			name: "李四",
			age:  18,
		}, {
			name: "王五",
			age:  20,
		},
	}
	sort.SliceStable(peoples, func(i, j int) bool {
		return peoples[i].age < peoples[j].age
	})
	fmt.Println(peoples)
}

總結

    排序演算法是演算法的基礎,理解演算法具體實現有利於鍛鍊思維,以及通過分析排序的優缺點,在合適的時候使用合適的排序方法。最重要的是高效和節省資源的平衡,通過研究go自帶的排序包,發現官方排序會根據資料量將排序分成不同的方式進行,不過最重要的還是快速排序。

相關文章