- 堆排序
堆结构就是用数组实现的完全二叉树结构
完全二叉树如果每颗子树的最大值在顶部就是大根堆(小根堆相反)
大根堆:
给定任意一个数组,将其转换成大根堆:
该数组为{1,5,2,3,9,7,4},将父节点比子节点小的数往下移
下标为i的左子为2i+1,如arr[2]=2 2i+1=5 它的左子arr[5]=7 右子arr[2i+2]=4
定义heapfify方法,将i位置的数与左子右子比较,父不是最大的就往下交换,再与子节点比较
func heapify(arr []int, index int, heapSize int) {
//如果该节点有左子
left := 2*index + 1
for left < heapSize {
//定义large 为 left right 父节点三者中最大值的下标
large := left
//如果右子存在且值大于左子
if left+1 < heapSize && arr[left+1] > arr[left] {
//更新下标为右节点
large = left + 1
}
//
if arr[index] > arr[large] {
//更新下标为父节点
large = index
//最大是自己就不用排了
break
}
//把父跟子换位置
Swap(arr, index, large)
index = large
//到了新位置,继续往下比较 直到比两个儿子都大或者没有儿子
left = 2*index + 1
}
}
大根堆的根节点肯定是最大的数,我们将根节点与数组最右边的数交换,就得到该数组最大的数,再讲index=0的进行heapify,得到大根堆,将根节点与数组最右边-1的数交换,周而复始,完成堆排序
package main
import (
"fmt"
"sort"
)
func Swap(arr []int, i, j int) {
if i == j {
return
}
arr[i] = arr[i] ^ arr[j]
arr[j] = arr[i] ^ arr[j]
arr[i] = arr[i] ^ arr[j]
}
func heap(arr []int) {
if len(arr) < 2 {
return
}
//将数组转换成大根堆
//这里是第一种思路,依次从左往右heapinsert
//for index, _ := range arr {
// heapInsert(arr, index)
//}
//这里是第二种思路,从右往左heapify,比第一种更快,时间复杂度O(n)
for i := len(arr) - 1; i >= 0; i-- {
heapify(arr, i, len(arr))
}
heapSize := len(arr) //这里用headsize指定arr长度,就可以避免再开一个数组存结果
for heapSize > 0 {
//每次提取根节点(最大的数),然后将最后一个节点放到根节点
Swap(arr, 0, heapSize-1)
heapSize--
//因为根节点是新人,将它heapify一次,就又能得到大根堆,根节点就是最大的,周而复始,直到heap为空
heapify(arr, 0, heapSize)
}
}
func heapInsert(arr []int, index int) {
for arr[index] > arr[(index-1)/2] {
Swap(arr, index, (index-1)/2)
index = (index - 1) / 2
}
sort.Ints(arr)
}
func heapify(arr []int, index int, heapSize int) {
//如果该节点有左子
left := 2*index + 1
for left < heapSize {
//定义large 为 left right 父节点三者中最大值的下标
large := left
//如果右子存在且值大于左子
if left+1 < heapSize && arr[left+1] > arr[left] {
//更新下标为右节点
large = left + 1
}
//
if arr[index] > arr[large] {
//更新下标为父节点
large = index
//最大是自己就不用排了
break
}
//把父跟子换位置
Swap(arr, index, large)
index = large
//到了新位置,继续往下比较 直到比两个儿子都大或者没有儿子
left = 2*index + 1
}
}
func main() {
arr := []int{1, 3, 4, 2, 5, 3, 9, 7}
heap(arr)
fmt.Println(arr)
}
- 桶排序
给一个数组 1 5 2 7 4 1,求排序后结果
定一个长度为10(十进制为10,三进制为3)的数组 count ,记录下标0 1 2 3 4 5 6 7 8 9的个数,比如1有两个,所以count[1]=2,count[5]=1,count[2]=1
那么能得到count[0,2,1,0,1,1,0,1,0,0] ,遍历count得到1 1 2 4 5 7
现在我们加大难度,求10 13 20 3 23 9 19 的排序结果
先排个位数,定一个长度为0-9的数组 count ,记录下标0 1 2 3 4 5 6 7 8 9的个数,比如个位数是9的有两个,所以count[9]=2,count[3]=3
那么能得到count[2,0,0,3,0,0,0,0,0,2]
所以排序后,个位数=1的在最左边两个,个位数为3在中间3个,个位数为9的在右边两个
arr最右边的19的个位数是9,对应最右边两个,排序后的下标就是2+3+2-1=6 ,所以bucket[6]=19,也就是下标=(count[i]+count[i-1]+…+count[0])-1
count=2 2 2 5 5 5 5 5 7
从右往左遍历题目arr,来到19,对应下标7-1=6,bucket[6]=19 count=2 2 2 5 5 5 5 5 6
来到9,对应下标6-1=5, bucket[5]=9 count= 2 2 2 5 5 5 5 5 5
来到23 ,对应下标5-1=4 ,bucket[4]=23 count = 2 2 2 4 5 5 5 5 5
…
得到bucket=[0 20 13 3 23 9 19] ,将它复制到arr中
再同理对arr十位数排序,得到 [0 3 9 13 19 20 23] ,由此完成全部排序
代码实现
package main
import (
"fmt"
)
func radixSort(arr []int) {
if len(arr) < 2 {
return
}
rS(arr, 0, len(arr)-1, maxBits(arr))
}
// 求最大位数
func maxBits(arr []int) (bits int) {
max := 0
for _, a := range arr {
if a > max {
max = a
}
}
for max != 0 {
max /= 10
bits++
}
return bits
}
func rS(arr []int, l, r, digit int) {
bucket := make([]int, len(arr))
for d := 1; d <= digit; d++ {
count := make([]int, 10)
for _, a := range arr {
ad := getDigit(a, d)
count[ad]++
}
for i, _ := range count {
if i > 0 {
count[i] += count[i-1]
}
}
for i := len(arr) - 1; i > 0; i-- {
ad := getDigit(arr[i], d)
bucket[count[ad]-1] = arr[i]
count[ad]--
}
for i, a := range bucket {
arr[i] = a
}
fmt.Println(arr, count)
}
}
func getDigit(num, digit int) int {
pow := 1
if digit > 1 {
for i := 1; i < digit; i++ {
pow *= 10
}
}
return num / pow % 10
}
func main() {
arr := []int{10, 13, 20, 3, 23, 9, 19}
radixSort(arr)
fmt.Println(arr)
}