二叉堆博客:https://www.cnblogs.com/kubidemanong/p/9711705.html
二叉堆的特点:
1.具有完全二叉树的特征:https://www.cnblogs.com/daniumeng/p/8598097.html
满二叉树是一颗特殊的完全二叉树,但完全二叉树不一定是满二叉树
完全二叉树,除了最下一层k以外,每一层都有2^(k-1)个节点
不同的是,二叉树一般菜用链表的方式来实现,但是二叉堆采用数组的方式来存储。
根据完全二叉树的特点,假如一个节点的下标为n,则可以求得他的左孩子下标为2*n+1,右孩子为2*n+2
2.任何一个父节点的值都大于等于他左右子节点的值,或者小于等于它左右子节点的值
二叉堆的三个主要操作:
1.插入:本着插入节点后,其依然是完全二叉树的规则,将新节点插到完全二叉树的最后一个位置
然后进行调整,让新插入的节点与其父节点进行比较,若新节点小于父节点,则让新节点上浮,然后继续与新的父节点进行比较,知道夫几点的值小于或者等于该节点,才停止,完成插入操作
2.删除:一般对根节点进行删除操作,本着插入节点后,依然是完全二叉树的规则,所以删除根节点后,用二叉树的最后一个元素顶替上来,然后再经i选哪个调整,与其子节点比较,判断两个子节点哪个更小,然后与其父节点比较,如果父节点大,那么交换节点,再往下进行比较,直到子节点大于等于父节点为止,完成删除操作
3.构建二叉堆:将一个无序的完全二叉树调整成二叉堆,那么需要将所有的非叶子节点一次下沉。下沉的顺序是从最后一个非叶子节点开始,一次往上。
堆排序的步骤: https://yq.aliyun.com/articles/638038
1.把无序数组构建成二叉堆
2.循环删除堆顶元素,以到集合尾部,调节堆产生新的堆顶
那么如何实现:
有一个无序数组,通过从下往上的顺序,将除了最后一行的每个元素下沉变成最大堆
然后再通过(length-1)--的方式循环删除堆顶元素(交换栈顶元素)并调节产生新的堆顶
直到i=0为止
package three;
import java.util.Arrays;
//最大堆
public class HeapSort {
/**
*
* 下沉调整
*
* @param array
* 待调整的堆
*
* @param parentIndex
* 要下沉的父节点
*
* @param parentIndex
* 堆的有效大小
*
*/
public static void downAdjust(int[] array, int parentIndex, int length) {
// temp保存父节点值,用于最后的赋值
int temp = array[parentIndex];
int childIndex = 2 * parentIndex + 1;
while (childIndex < length) {
// 如果有右孩子,且右孩子大于左孩子的值,则定位到右孩子
if (childIndex + 1 < length && array[childIndex + 1] > array[childIndex]) {
childIndex++;
}
// 如果父节点小于任何一个孩子的值,直接跳出
if (temp >= array[childIndex])
break;
// 无需真正交换,单向赋值即可
array[parentIndex] = array[childIndex];
parentIndex = childIndex;
childIndex = 2 * childIndex + 1;
}
array[parentIndex] = temp;
}
/**
*
* 堆排序
*
* @param array
* 待调整的堆
*
*/
public static void heapSort(int[] array) {
// 1.把无序数组构建成二叉堆。
for (int i = (array.length - 2) /
2; i >= 0; i--) {
downAdjust(array, i, array.length);
}
System.out.println(Arrays.toString(array));
// 2.循环删除堆顶元素,移到集合尾部,调节堆产生新的堆顶。
for (int i = array.length - 1; i > 0; i--) {
// 最后一个元素和第一元素进行交换
int temp = array[i];
array[i] = array[0];
array[0] = temp;
// 下沉调整最大堆
downAdjust(array, 0, i);
}
}
public static void main(String[] args) {
int[] arr = new int[] {1,3,2,6,5,7,8,9,10,0};
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
}
堆排序的空间和时间复杂度:
空间复杂度:O(1) 因为没有占用额外的空间
时间复杂度:O(logn) 第一步需要进行n/2次循环,每次都要排序一次,计算规模:n/2 * logn
第二步需要进行n-1次循环,每次都要排序一次,计算规模:(n-1)*logn
由于两者是并列关系,所以整体的时间复杂度同样是O(nlogn)
堆排序与快速排序的相同不同点:?? https://yq.aliyun.com/articles/638038