堆技术细节与堆排序【原创】
参考:
https://www.jianshu.com/p/6b526aa481b1(数据结构:堆)
https://www.runoob.com/w3cnote/heap-sort.html(堆排序)
堆的性质
堆是具有以下性质的完全二叉树,每个节点的值都大于或等于其左右孩子节点的值称为最大堆,反之为最小堆。
注意:没有要求节点的左孩子的值和右孩子的值的大小关系。
堆的存储
1,堆使用数组实现,不是结点和指针。
2,堆的属性可以让堆和数组元素直接对应起来
这个数组arr逻辑上就是一个堆。
从这里我们可以得出以下性质(重点)
对于大顶堆:arr[i] >= arr[2i + 1] && arr[i] >= arr[2i + 2]
对于小顶堆:arr[i] <= arr[2i + 1] && arr[i] <= arr[2i + 2]
堆结点与数组小标关系:
1,index从0开始
2,父节点为 i,左节点:2i+1;右结点:2i+2
3,子节点为 i,floor( (i-1)/2) 等价于 (i-1)>>1
核心操作
上浮操作
当前结点与父节点比较,小于父节点则交换(最小堆情况下,最大堆相反),递归向上
func HeapUp(arr []int,index int) { for pi:=(index-1)>>1;index>0;pi=(index-1)>>1{ piv:=arr[pi]//切片本身是引用型 iv:=arr[index] if piv>iv{ arr[index],arr[pi] = arr[pi],arr[index] }else { break } index=pi } //return arr } //test arr:=[]int{5,3,6,4,7,2} HeapUp(arr,len(arr)-1) fmt.Println(arr)
下沉操作
当前结点与左右子节点比较,大于较小的节点则交换(最小堆的情况下,最大堆是小于较大的节点),递归向下
func HeapDown(arr []int,index int) { for li,ri :=2*index+1,2*index+2;ri<len(arr); li,ri =2*index+1,2*index+2{//第3句pi=(index-1)>>1不能省略,这里涉及到for循环的本质 liv:=arr[li]//切片本身是引用型 riv:=arr[ri] iv:=arr[index] small:=liv si:=li if small>riv{ small = riv si=ri } if iv>small{ arr[index],arr[si] = arr[si],arr[index] fmt.Println(index,si) }else { break } index=si } } //测试 arr:=[]int{9,5,3,6,4,7,2} HeapDown(arr,0) fmt.Println(arr)
插入
1,先把元素插入到末尾
2,使用上浮操作,对插入的尾部元素
删除:最小头元素
1,将头尾元素交换
2,删除交换后的尾部元素
3,使用下层操作,对交换后的呕吐不元素
获取
直接获取小标为0的元素
堆排序
堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),是不稳定排序
算法步骤
-
创建一个堆 H[0……n-1];
-
把堆首(最大值)和堆尾互换;
-
把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置;
-
重复步骤 2,直到堆的尺寸为 1。
show me the code
func heapSort(arr []int) []int { arrLen := len(arr) buildMaxHeap(arr, arrLen) for i := arrLen - 1; i >= 0; i-- { swap(arr, 0, i) arrLen -= 1 heapify(arr, 0, arrLen) } return arr } func buildMaxHeap(arr []int, arrLen int) { for i := arrLen / 2; i >= 0; i-- { heapify(arr, i, arrLen) } } func heapify(arr []int, i, arrLen int) { left := 2*i + 1 right := 2*i + 2 largest := i if left < arrLen && arr[left] > arr[largest] { largest = left } if right < arrLen && arr[right] > arr[largest] { largest = right } if largest != i { swap(arr, i, largest) heapify(arr, largest, arrLen) } } func swap(arr []int, i, j int) { arr[i], arr[j] = arr[j], arr[i] }