堆排序——大根堆

package heap

import (
	"fmt"
	"testing"
)

func TestHeap(t *testing.T) {
  h := NewMyMaxHeap(10)
  h.push(12)
  h.push(32)
  h.push(32)
  h.push(392)
  h.push(3922)
  h.push(3002)
  fmt.Println(h.Heap)
  fmt.Println(h.pop())
  fmt.Println(h.pop())
  fmt.Println(h.pop())
  fmt.Println(h.pop())
  fmt.Println(h.pop())
  fmt.Println(h.pop())
}



/*
堆结构
 1.堆结构就是用数组实现的完全二叉树结构
 2.完全二叉树中如果每棵子树的最大值都在顶部就是大根堆
 3.完全二叉树中如果每棵子树的最小值都在顶部就是小根堆
 4.堆结构的heapInsert与heapify操作
 5.堆结构的增大和减小
 6.优先队列结构,就是堆结构


 完全二叉树 该层是满的  或 从左向右变满的状态中

                     1
                  /    \
                 2      3
              /   \   /   \
             4     5 6     7


数组形式表示:
[ 1, 2, 3, 4, 5, 6, 7]
左孩子: 2*i + 1
右孩子: 2*i + 2
父节点: (i-1)/2

有的实现中 弃用0位置 从1 开始
左孩子: 2*i       i << 1
有孩子: 2*i + 1   i << 1 + 1
父节点: i/2       i >> 2
使用位运算可能速度快?

堆:在完全二叉树上有其他要求,大根堆和小根对

*/

type MyMaxHeap struct {
	Heap     []int
	Limit    int
	HeapSize int  // 已经收集了多少个数,及其新来的数放在哪里
}

func NewMyMaxHeap(limit int) *MyMaxHeap {
	return &MyMaxHeap{
		Heap:     make([]int,limit),
		Limit:    limit,
		HeapSize: 0,
	}
}

func (h *MyMaxHeap)isEmpty() bool {
	return h.HeapSize == 0
}

func (h *MyMaxHeap)isFull() bool {
	return h.HeapSize == h.Limit
}

func (h *MyMaxHeap)push(val int)  {  //高度 logN
	if h.HeapSize == h.Limit {
		return                  // 未加入错误处理,暂时return
	}
	h.Heap[h.HeapSize] = val
	h.heapInsert()
	h.HeapSize++
}

func (h *MyMaxHeap)heapInsert()  {
	for index := h.HeapSize; h.Heap[index] > h.Heap[ (index - 1 ) / 2 ]; index = (index - 1) / 2 {   // 自己的值 > 父亲节点的值
		h.Swap(index,(index- 1) / 2)
	}
}

func (h *MyMaxHeap)pop() int {
	if h.HeapSize == 0 {
		return -1  //未加入错误处理,暂时用-1替代
	}

	ans := h.Heap[0]

	h.HeapSize--
	h.Swap(0,h.HeapSize)   // 最后一个元素和第一个元素 交换
	h.heapify(0)       // 堆平衡  下沉操作

	return ans
}

func (h *MyMaxHeap)heapify( index int)  { // logN
	left := index * 2 + 1   // 找到做孩子位置
	for left < h.HeapSize { // 左孩子位置小于堆的size, 左孩子 >= 堆size 时,证明父节点没有孩子
		largest := left     // 左右孩子节点中选出一个大的
		if (left + 1) < h.HeapSize && h.Heap[left + 1] > h.Heap[left] { // 有右孩子,并且右孩子比左孩子大
			largest = left + 1
		}

		if h.Heap[largest] <= h.Heap[index] {  // 如果寻找到的最大的孩子的值<= 父节点的值,证明父节点的位置刚刚好
			break
		}
		h.Swap(index,largest)  //下滑操作
		index = largest        // 当前节点作为父节点
		left = index * 2 + 1   // 从当前节点继续下滑
	}
}


func (h *MyMaxHeap) Swap(i, j int)  {
	if i == j {  // 防清零
		return
	}
	h.Heap[i] ^= h.Heap[j]
	h.Heap[j] ^= h.Heap[i]
	h.Heap[i] ^= h.Heap[j]
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

metabit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值