堆:
二叉堆满足二个特性:
1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。
一般用数组实现二叉堆
如果用长度为N+1的数组 A[N+1] 来表示一个大小为N的堆,不会使用A[0],把堆元素放在A[1] -A[n]中, 根节点在A[1] 中,它的左右子节点在分别在A[2]和A[3]中,位置k的结点的父结点的位置为 k/2(向下取整,设为int i = k/2 就自动向下取整了) ,而它的两个子结点的位置则分别为2k和2k+1。
如果A[0]也用上 i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。 (记这个吧)
堆实现优先队列有两种关键操作:
1)插入
将新元素加到数组尾,然后把这个新元素上浮(swim)到合适的位置
2)删除
删除一般就是删除最大元素,也就是根节点 A, 数组第一个
一般采取的方法是 将根节点与数组最后一个 交换,然后 下沉(sink)新根节点, 把数组最后一个给删掉,--N
堆排序
然后是堆排序
基本思想是,先把一个数组构造成一个堆,然后再反复删除最大元素
构造堆有个小窍门,假如A[0]是根节点,一共有N个元素,那么 从N/2-1到0 开始下沉,N/2到最后不用管它
然后再删除最大元素,第一次将A[0]与A[n - 1]交换,再对A[0]下沉 重新恢复堆。第二次将A[0]与A[n – 2]交换,再对A[0…n - 3]重新恢复堆,重复这样的操作直到A[0]与A[1]交换。由于每次都是将最大的数据并入到后面的有序区间,故操作完成后整个数组就有序了
由于每次重新恢复堆的时间复杂度为O(logN),共N - 1次重新恢复堆操作,再加上前面建立堆时N / 2次向下调整,每次调整时间复杂度也为O(logN)。二次操作时间相加还是O(N * logN)。故堆排序的时间复杂度为O(N * logN)。
参考资料:https://blog.csdn.net/MoreWindows/article/details/6709644