堆结构
堆结构就是用数组实现的完全二叉树结构(有右子节点时,必有左子节点)
堆的类型有两种:
堆中的方法:
堆结构优点(以下解释以大根堆为例):
下面用代码示例来演示堆结构:
package com.leftGod;
/**
* 基础堆结构
*
* 基础:
* 求父节点下标:(i-1)/2
* 求左孩子节点下标:i*2+1
* 求右孩子节点下标:i*2+2
*
* @author zhao.hualuo
* Create at 2022/4/2
*/
public class BaseHeap {
/** 堆当前使用量 */
private static int heapSize = 0;
/** 堆数组,用来存放当前元素 */
private static int[] heapArr = new int[4];
/**
* heapInsert
*
* @param newValue 要插入到堆中的新值
*/
public static void heapInsert(int newValue) {
//1、将这个新元素放到堆的最后一个位置,堆的长度+1
heapArr[heapSize] = newValue;
//1、将现在的数组重新转化成堆
int index = heapSize;
while (index>=0 && heapArr[index] > heapArr[(index-1)/2]) {
swap(index, (index-1)/2);
index = (index-1)/2;
}
//堆长度+1
heapSize++;
//判断堆是否需要扩容
expansion();
}
/**
* heapify
* 代码中注释1和注释2只会有一个成立
*
* @param index 要移除的元素下标
* @return 移除的元素值
*/
public static int heapify(int index) {
int returnValue = heapArr[index];
//将最后一个位置的元素交换到要移除的这个元素位置上
swap(index, heapSize-1);
//1、看看这个元素是不是比父元素要大。若是,需要上移
while (index>=0 && heapArr[index] > heapArr[(index-1)/2]) {
swap(index, (index-1)/2);
index = (index-1)/2;
}
//2、看看这个元素是不是比子元素要小。若是,需要下沉
int left = index*2+1;
while (left < heapSize) {
//看看两个子元素那个大,下一步要和大的进行比较替换
int maxSonIndex = left+1<heapSize && heapArr[left+1] >heapArr[left] ? left+1 : left;
//当前元素和较大的那个儿子作比较,若父亲比两个儿子都大,匹配成功,循环结束
if (heapArr[index] >= heapArr[maxSonIndex]) {
break;
}
//走到这一步,说明儿子比老子大,老子和儿子要交换位置
swap(index, maxSonIndex);
//准备下一次循环
index = maxSonIndex;
left = left*2+1;
}
heapSize--;
return returnValue;
}
/**
* 堆自动扩容机制
*/
private static void expansion() {
//判断是否需要扩容
if (heapSize < heapArr.length) {
return;
}
//创建新数组,并复制
int[] newHeapArr = new int[heapArr.length*2];
System.arraycopy(heapArr, 0, newHeapArr, 0, heapArr.length);
heapArr = newHeapArr;
System.out.println("触发扩容,新堆长度:" + heapArr.length);
}
/**
* 将两个元素交换位置
*
* @param originIndex 原位置
* @param targetIndex 目标位置
*/
private static void swap(int originIndex, int targetIndex) {
if (originIndex == targetIndex) {
return;
}
heapArr[originIndex] = heapArr[originIndex] ^ heapArr[targetIndex];
heapArr[targetIndex] = heapArr[originIndex] ^ heapArr[targetIndex];
heapArr[originIndex] = heapArr[originIndex] ^ heapArr[targetIndex];
}
public static void main(String[] args) {
//测试heapInsert
heapInsert(15);
heapInsert(40);
heapInsert(9);
heapInsert(8);
heapInsert(32);
heapInsert(39);
heapInsert(35);
System.out.println("\n当前堆大小:" + heapArr.length + ",已占用堆空间:" + heapSize);
System.out.print("heapInsert结果:");
for (int i = 0; i < heapSize; i++) {
System.out.print(heapArr[i] + ", ");
}
System.out.println();
//[40, 32, 39, 8, 15, 9, 35, 0]
//测试heapify
//应该将8删除,用最后一个元素35来替换,35会和父亲32做一次heapInsert
heapify(3);
System.out.println("\n当前堆大小:" + heapArr.length + ",已占用堆空间:" + heapSize);
System.out.print("heapify结果:");
for (int i = 0; i < heapSize; i++) {
System.out.print(heapArr[i] + ", ");
}
//[40, 35, 39, 32, 15, 9, 8, 0]
}
}
上面示例的运行结果如下:
"C:\Program Files\Java\jdk1.8.0_212\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2.2\lib\idea_rt.jar=9226:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_212\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_212\jre\lib\rt.jar;D:\CodeWorkspace\PersonCode\demo\target\classes;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter\2.4.3\spring-boot-starter-2.4.3.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot\2.4.3\spring-boot-2.4.3.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-context\5.3.4\spring-context-5.3.4.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-aop\5.3.4\spring-aop-5.3.4.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-beans\5.3.4\spring-beans-5.3.4.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-expression\5.3.4\spring-expression-5.3.4.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.4.3\spring-boot-autoconfigure-2.4.3.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-logging\2.4.3\spring-boot-starter-logging-2.4.3.jar;C:\Users\Administrator\.m2\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;C:\Users\Administrator\.m2\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;C:\Users\Administrator\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;C:\Users\Administrator\.m2\repository\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;C:\Users\Administrator\.m2\repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;C:\Users\Administrator\.m2\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-core\5.3.4\spring-core-5.3.4.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-jcl\5.3.4\spring-jcl-5.3.4.jar;C:\Users\Administrator\.m2\repository\org\yaml\snakeyaml\1.27\snakeyaml-1.27.jar;C:\Users\Administrator\.m2\repository\com\gexin\platform\gexin-rp-sdk-http\4.1.0.5\gexin-rp-sdk-http-4.1.0.5.jar;C:\Users\Administrator\.m2\repository\com\gexin\platform\gexin-rp-sdk-template\4.0.0.24\gexin-rp-sdk-template-4.0.0.24.jar;C:\Users\Administrator\.m2\repository\com\gexin\platform\gexin-rp-sdk-base\4.0.0.30\gexin-rp-sdk-base-4.0.0.30.jar;C:\Users\Administrator\.m2\repository\com\google\protobuf\protobuf-java\2.5.0\protobuf-java-2.5.0.jar;C:\Users\Administrator\.m2\repository\com\gexin\platform\gexin-rp-fastjson\1.0.0.3\gexin-rp-fastjson-1.0.0.3.jar;C:\Users\Administrator\.m2\repository\com\getui\push\restful-sdk\1.0.0.1\restful-sdk-1.0.0.1.jar;C:\Users\Administrator\.m2\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;C:\Users\Administrator\.m2\repository\org\apache\httpcomponents\httpclient\4.5.13\httpclient-4.5.13.jar;C:\Users\Administrator\.m2\repository\org\apache\httpcomponents\httpcore\4.4.14\httpcore-4.4.14.jar;C:\Users\Administrator\.m2\repository\commons-codec\commons-codec\1.15\commons-codec-1.15.jar;C:\Users\Administrator\.m2\repository\com\google\code\gson\gson\2.8.6\gson-2.8.6.jar" com.leftGod.BaseHeap
触发扩容,新堆长度:8
当前堆大小:8,已占用堆空间:7
heapInsert结果:40, 32, 39, 8, 15, 9, 35,
当前堆大小:8,已占用堆空间:6
heapify结果:40, 35, 39, 32, 15, 9,
Process finished with exit code 0