完全二叉树
完全二叉树从根结点到倒数第二层满足完美二叉树,最后一层可以不完全填充,其叶子结点都靠左对齐。
完全二叉堆
结构上是完全二叉树,并且满足堆序性,也就是父节点的值要不小于(大顶堆)或不大于(小顶堆)子节点的值。
大顶堆
package com.kyrie.test.heap;
import java.util.ArrayList;
/**
* @author kyrie
*/
public class MaxHeap {
private ArrayList<Integer> nums = new ArrayList<>();
public MaxHeap() {
}
public MaxHeap(ArrayList<Integer> nums) {
this.nums = nums;
this.constructHeap();
}
/**
*
* @return 仅返回最大的数,即第一个数
* @throws Exception
*/
public int getMax() throws Exception {
if(nums.size()<=0) throw new Exception();
return nums.get(0);
}
/**
*
* @return Max
* @throws Exception
* 将第一个数返回后,把最后一个数替换第一个数,再检测下滤
*/
public int deleteMax() throws Exception {
if(nums.size()<=0) throw new Exception();
int res=nums.get(0);
nums.set(0,nums.get(nums.size()-1));
nums.remove(nums.size()-1);
this.percolateDOwn(0);
return res;
}
/**
*
* @param ele
* 加入一个元素到数组末尾,然后上浮
*/
public void add(int ele){
int len = nums.size();
nums.add(ele);
this.upRise(len);
}
/**
*
* 将最后一个节点,与其父节点比较,递归上浮
*/
private void upRise(int i){
if(i==0) return;
int parent=i/2;
if(nums.get(i)>nums.get(parent)){
swap(parent,i);
upRise(parent);
}
return;
}
/**
*
* 从倒数第一个内部节点开始下滤,使得整个堆有序
*/
public void constructHeap(){
int len=nums.size();
// 最后一个内部节点的下标
int lastInternal = len/2-1;
// 从下往上下滤,按照弗洛伊德算法,时间复杂度为O(n)
for (int i = lastInternal; i >= 0; i--) {
this.percolateDOwn(i);
}
}
/**
*
* @param i 将被下滤的数
*/
private void percolateDOwn(int i ){
int last = this.nums.size();
int L = i * 2+1;
int R = L + 1;
int minLR = -1;
if (L >= last && R >= last) {//如果当前节点为叶子节点,下滤结束
return;
}
if (L < last && R >= last) {
minLR = L;
}else{
minLR = this.nums.get(L) < this.nums.get(R) ? R : L;
}
if (this.nums.get(i)>= this.nums.get(minLR)) {//不需要下滤
return;
} else {
swap(i,minLR);
this.percolateDOwn(minLR);//继续下滤
}
}
private void swap(int i,int j){
int temp=nums.get(i);
nums.set(i,nums.get(j));
nums.set(j,temp);
}
public int size(){
return nums.size();
}
public static void main(String[] args) throws Exception {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(4);
arrayList.add(56);
arrayList.add(21);
arrayList.add(-76);
arrayList.add(100);
arrayList.add(42);
MaxHeap maxHeap = new MaxHeap(arrayList);
System.out.println(maxHeap.deleteMax());
System.out.println(maxHeap.deleteMax());
System.out.println(maxHeap.deleteMax());
}
}
小顶堆
小顶堆的构建方式和大顶堆大同小异,就不展示构建代码
堆排序(T:O(nlogn),S:O(1))
package com.kyrie.test.heap;
public class HeapSort{
public void heapSort(int[] nums) {
for (int j = nums.length-1; j > 0; j--) {
int t = nums[j];
nums[j] = nums[0];
nums[0] = t;
this.percolateDOwn(0, nums, j );
}
}
private void percolateDOwn(int i, int[] nums, int last) {
int L = i*2+1;
int R = L + 1;
int minLR = -1;
if (L >= last && R >= last) {//如果当前节点为叶子节点,下滤结束
return;
}
if (L < last && R >= last) {
minLR = L;
}
if (L < last && R < last) {
minLR = nums[L] < nums[R] ? R : L;
}
if (nums[i] >= nums[minLR]) {//不需要下滤
return;
} else {
int t = nums[i];
nums[i] = nums[minLR];
nums[minLR] = t;
this.percolateDOwn(minLR, nums, last);//继续下滤
}
}
public void heapify(int[] nums) {
// 最后一个内部节点的下标
int lastInternal = nums.length/2-1;
// 从下往上下滤,按照弗洛伊德算法,时间复杂度为O(n)
for (int i = lastInternal; i >= 0; i--) {
this.percolateDOwn(i, nums, nums.length);
}
}
public static void main(String[] args) {
int[] nums = new int[] { 8,4,2,9,5,9,467,-4,3};
HeapSort heapSort = new HeapSort();
heapSort.heapify(nums);
heapSort.heapSort(nums);
System.out.println("kyrie");
}
}