[TOC]
概述
堆是一种特殊的树,只要满足下面两个条件,它就是一个堆:
- 堆是一颗完全二叉树;
- 堆中某个节点的值总是不大于(或不小于)其父节点的值。
其中,我们把根节点最大的堆叫做大顶堆,根节点最小的堆叫做小顶堆。
二叉树概念
- 满二叉树是指所有层都达到最大节点数的二叉树。
- 完全二叉树是指除了最后一层其它层都达到最大节点数,且最后一层节点都靠左排列。
我们可以看见,完全二叉树的节点都是比较紧凑的,且只有最后一层是不满的,所以使用数组是最节省空间的。
堆
堆也是一颗完全二叉树,但是它的元素必须满足每个节点的值都不大于(或不小于)其父节点的值。比如下面这个堆:
堆的实现
插入元素
在完全二叉树中,插入的节点与它的父节点相比,如果比父节点小,就交换它们的位置,再往上和父节点相比,如果比父节点小,再交换位置,直到比父节点大为止。
在数组中,插入的节点与n/2位置的节点相比,如果比n/2位置的节点小,就交换它们的位置,再往前与n/4位置的节点相比,如果比n/4位置的节点小,再交换位置,直到比n/(2^x)位置的节点大为止。
这就是插入元素时进行的堆化,也叫自下而上的堆化。
从插入元素的过程,我们知道每次与n/(2^x)的位置进行比较,所以,插入元素的时间复杂度为O(log n)。
删除堆顶元素
只能删除堆顶元素,不能删除其他位置的元素,其他位置实际上都是乱序的,只有堆顶能保证是最大或者最小
建堆
假定给定一组乱序的数组,我们该怎么建堆呢?
如下图所示,我们模拟依次往堆中添加元素。
(1)插入6这个元素,只有一个,不需要比较;
(2)插入8这个元素,比6大,不需要交换;
(3)插入3这个元素,比下标3/2=1的位置上的元素6小,交换位置;
(4)插入2这个元素,比下标4/2=2的位置上的元素8小,交换位置,比下标2/2=1的位置上的元素3小,交换位置;
(5)…
(10)最后,全部插入完成,即完成了建堆的过程。
堆排序
我们直接把堆顶的元素与第n个元素交换位置,再把前(n-1)个元素堆化,再把堆顶元素与第(n-1)个元素交换位置,
再把前(n-2)个元素堆化,..,,进行下去,最后,数组中的元素就整个变成倒序的了,也就排序完了。
堆使用
1 | # 默认小顶堆(最小堆) |
参考
https://leetcode-cn.com/circle/article/bNtb4J/