堆
- 堆结构就是用数组实现的完全二叉树
- 完全二叉树如果子树最大值在顶部就是大根堆
- 完全二叉树如果子树最小值都在顶部就是小根堆
- 优先队列操作,就是堆操作
堆排序
1.先让整个数组都变成大根堆,建立堆过程。
1) 从上到小下,时间复杂度为O(N*logN)
2)从下到上的方法,时间复杂度为0(N)
2. 把堆的最大值和堆末尾的值交换,然后减少堆的大小之后再去调整堆,一直周而复始,时间复杂度为O(N * logN)
3. 堆的大小减小为0后,排序完成。
private static void heapSort(int[] arr) {
//先找到非叶子节点,构建大根堆
for (int i = (arr.length - 1) / 2; i >= 0; i--) {
//从i向下找,保证每个元素都能被找到,如果从0开始如果最大值正好在第一位,
// 后面无法比较,找到某一个叶子节点的最大值
heapify(arr, i, arr.length);
}
int heapSize = arr.length;
while (heapSize > 1) {
swap(arr, --heapSize, 0);
heapify(arr,0, heapSize);
}
}
private static void heapify(int[] arr, int index, int heapSize) {
int left = 2 * index + 1;
while (left < heapSize) {
int max = left;
//左数、右数比较比较
//如果left+ 1不超过树的长度,并且右数比左数大,max设置为左数
if (left + 1 < heapSize && arr[left + 1] > arr[left]) {
max = left + 1;
}
//index和左右两个数最大值比较,找到最大的
max = arr[max] < arr[index] ? index : max;
//如果最大值与index值相同,
if (arr[max] == arr[index]) {
break;
}
//如果最大值比index大,则交换最大值
if (arr[max] > arr[index]) {
swap(arr, index, max);
}
//下沉
index = max;
left = 2 * index + 1;
}
}
堆排序的拓展题目
已知一个几乎有序的数组,几乎有序是指,如果把数组排好序的话,每一个元素的移动距离不超过k,并且k对于数组来说比较小,请选择一个合适的算法进行排序。
几乎有序的数组,移动距离不超过k,那么意味着这个数的最小值就在这个k长度数组里面,构建最小堆,然后k个一比较,比较到结束,把剩余的重新比较。
private static void sortAlmostArr(int[] arr, int k, int heapSize) {
//先将k元素拷贝下来
int[] temp = Arrays.copyOf(arr, k);
//构建小根堆,保证父亲节点都是最大的
for (int i = (k -1)/2; i >=0; i--) {
heapiSmall(temp, i, k);
}
//从k位向后走,不断构建小根堆开始
for (int i = k; i < heapSize; i++) {
//由于构建了小根堆,最小值index为0将temp第一个元素获取出来就是他的
int tep = temp[0];
temp[0] = arr[i];
arr[i-k] =tep;
//从0位置上不断的找最小值
heapiSmall(temp, 0, k);
}
//正好begin走到n-k位置上,end越界了,所以从begin到end要重新排序
for(int i = heapSize - k ; i < heapSize; i++) {
arr[i] = temp[0];
swap(temp, 0, --k);
heapiSmall(temp,i, k);
}
}
private static void heapiSmall(int[] temp, int index, int heapSize) {
int left = 2 * index + 1;
while (left < heapSize) {
int max = left;
if (left + 1 < heapSize && temp[left+ 1] < temp[left]) {
max = left + 1;
}
if (temp[index] < temp[max]) {
max = index;
}
if (temp[index] == temp[max]) {
break;
}
if (temp[max] < temp[index]) {
swap(temp, max, index);
}
index = max;
left = 2 * index + 1;
}
}