堆数据结构的介绍
堆是一种重要的数据结构,为一棵完全二叉树, 底层如果用数组存储数据的话,假设某个元素为序号为i(Java数组从0开始,i为0到n-1),如果它有左子树,那么左子树的位置是2i+1,如果有右子树,右子树的位置是2i+2,如果有父节点,父节点的位置是(n-1)/2取整。分为最大堆和最小堆,最大堆的任意子树根节点不小于任意子结点,最小堆的根节点不大于任意子结点。所谓堆排序就是利用堆这种数据结构来对数组排序,我们使用的是最大堆。处理的思想和冒泡排序,选择排序非常的类似,一层层封顶,只是最大元素的选取使用了最大堆。最大堆的最大元素一定在第0位置,构建好堆之后,交换0位置元素与顶即可。堆排序为原位排序(空间小), 且最坏运行时间是O(nlgn),是渐进最优的比较排序算法。
常见问题
1.最大的k个数:建立大小为k的最小堆,遍历原数组,依次与堆顶元素比较,若数组元素大于堆顶元素,则交换这两元素,并从堆顶调整元素
2.最小的k个数:建立大小为k的最大堆,遍历原数组,依次与堆顶元素比较,若数组元素小于堆顶元素,则交换这两元素,并从堆顶调整元素
代码样例
堆的调整算法:
/**
* 堆的调整算法
* 递归调整
*
* @param arr
* :原数组
* @param i
* :当前下标
*/
public static void adjustMaxHeap(int[] arr, int i) {
int lchild = lchild(i);
int rchild = rchild(i);
int largest;
if (lchild < heapsize && arr[i] < arr[lchild]) {
largest = lchild;
} else {
largest = i;
}
if (rchild < heapsize && arr[largest] < arr[rchild]) {
largest = rchild;
}
if (largest == i || largest >= arr.length) {
return;// 未与孩子节点交换,或者超出范围,直接return到上一级
}
// 将父节点与孩子节点交换
int temp = arr[largest];
arr[largest] = arr[i];
arr[i] = temp;
adjustMaxHeap(arr, largest);
}
建立最大堆:
/**
* 构建最大堆
* @param arr
*/
public static void buildMaxHeap(int[] arr) {
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adjustMaxHeap(arr, i);
}
}
堆排序:
//对一个最大堆heap排序
public static void heapSort(List<Integer> heap) {
for (int i = heap.size()-1; i > 0; i--) {
/*把根节点跟最后一个元素交换位置,调整剩下的n-1个节点,即可排好序*/
swap(heap,1, i);
adjust(heap,1, i - 1);
}
}