• 堆是一个完全二叉树
  • 每个节点的值都必须大于等于(或小于等于)其左右孩子节点的值

如果每个节点的值都大于等于左右孩子节点的值,这样的堆叫大顶堆;如果每个节点的值都小于等于左右孩子节点的值,这样的堆叫小顶堆。

插入:以大顶堆为例,从叶子结点插入,如果比父级元素大,则与父级元素交换位置,依次类推,直到到达根节点(小顶堆恰好相反)

删除:每次从堆顶删除元素后,需要从子节点中取值补齐堆顶,依次类推,直到叶子节点,就会致使存储堆的数组出现「空洞」,解决办法是将数组中的最后一个元素(最右边的叶子节点)移到堆顶,再重新对其进行堆化

应用场景:
1.优先级队列:在优先级队列中,数据的出队顺序不是先进先出,而是按照优先级来,优先级最高的,最先出队,背后的原理就是不断删除堆顶元素。
2.TopK排行榜:日常开发中,经常遇到类似求销售额Top10,浏览数Top10,点赞数Top10之类的需求,也可以通过堆排序来实现,原理就是维护一个大小为 K 的小顶堆,有新数据进入后,如果值比堆顶元素大,则删除堆顶元素,当前元素插入堆顶,并进行调整,最终这个小顶堆就是 TopK 数据了。

PHP

class Heap
{
    private $arr = [];
    private $count = 0;

    public function push($num)
    {
        $this->count++;
        $this->arr[$this->count] = $num;
        $current = $this->count;
        $parent = floor($current / 2);
        while ($parent > 0 && $this->arr[$parent] < $this->arr[$current]) {
            $tmp = $this->arr[$current];
            $this->arr[$current] = $this->arr[$parent];
            $this->arr[$parent] = $tmp;
            $current = $parent;
            $parent = floor($current / 2);
        }
    }

    public function pull()
    {
        if ($this->count == 0) {
            return false;
        }
        $return = $this->arr[1];
        $this->arr[1] = $this->arr[$this->count];
        $this->count--;
        $current = 1;
        while (true) {
            $next = $current;
            if ($current * 2 <= $this->count && $this->arr[$current * 2] > $this->arr[$current]) {
                $next = $current * 2;
            } 
            if ($current * 2 + 1 <= $this->count && $this->arr[$current * 2 + 1] > $this->arr[$next]) {
                $next = $current * 2 + 1;
            }
            if ($next == $current) {
                break;
            }
            $tmp = $this->arr[$next];
            $this->arr[$next] = $this->arr[$current];
            $this->arr[$current] = $tmp;
            $current = $next;
        }
        return $return;
    }

    public function __toString()
    {
        return json_encode(array_values($this->a));
    }
}

$heap = new Heap;
$data = range(1, 10);
shuffle($data);
foreach ($data as $num) {
    $heap->push($num);
}
print_r($heap);
$reData = [];
while ($re = $heap->pull()) {
    $reData[] = $re;
}
print_r($reData);

GO

package main

import (
	"fmt"
	"math"
)

type Heap struct {
	arr []int
	count int
}

func main() {
	heap := newHeap()
	for i := 1; i <= 10; i++ {
		heap.push(i)
	}
	fmt.Println(heap.arr)
	for {
		re,empty := heap.pull()
		if empty == true {
			break
		}
		fmt.Println(re)
	}
}

func newHeap() *Heap {
	return &Heap{
		count: 0,
	}
}

func (heap *Heap) push(num int) {
	heap.count++
	heap.arr = append(heap.arr, num)
	current := heap.count
	parent := int(math.Floor(float64(current) / 2))
	for {
		if parent == 0 {
			break;
		}
		if heap.arr[parent - 1] >= heap.arr[current - 1] {
			break;
		}
		tmp := heap.arr[parent - 1]
		heap.arr[parent - 1] = heap.arr[current - 1]
		heap.arr[current - 1] = tmp
		current = parent
		parent = int(math.Floor(float64(current) / 2))
	}
}

func (heap *Heap) pull() (re int, empty bool) {
	if heap.count == 0 {
		return -1, true
	}
	re = heap.arr[0]
	empty = false
	heap.arr[0] = heap.arr[heap.count - 1]
	heap.count--
	current := 1
	var next int
	for {
		next = current
		if current * 2 < heap.count && heap.arr[current * 2 - 1] > heap.arr[current - 1] {
			next = current * 2
		}
		if current * 2 + 1 < heap.count && heap.arr[current * 2] > heap.arr[next - 1] {
			next = current * 2 + 1
		}
		if next == current {
			break
		}
		tmp := heap.arr[current - 1]
		heap.arr[current - 1] = heap.arr[next -1]
		heap.arr[next - 1] = tmp
		current = next
	}
	return
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值