大顶堆小顶堆笔记
堆是一颗完全二叉树
堆分为两类:
1、最大堆(大顶堆):堆的每个父节点都大于其孩子节点;
2、最小堆(小顶堆):堆的每个父节点都小于其孩子节点;
堆的存储:
一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2,i从0开始
堆排序:
堆的第一个元素要么是最大值(大顶堆),要么是最小值(小顶堆),这样在排序的时候(假设共n个节点),直接将第一个元素和最后一个元素进行交换,然后从第一个元素开始进行向下调整至第n-1个元素。所以,如果需要升序,就建一个大堆,需要降序,就建一个小堆。
堆排序的步骤分为三步:
1、建堆(升序建大堆,降序建小堆)
2、交换数据
3、向下调整
实现
注释基完整,网上得有一些问题,修改了没问题,测试过了(代码就是网上的)
重点在于元素交换操作
项目结构
MinHeap
package com.example.taco.minHeapTest;
import lombok.Data;
/**
* 最小堆实现
*
* @author lh
* @date 2022/01/13 20:52
*/
@Data
public class MinHeap {
/**
* 堆容器数组
*/
private Node[] heapArray;
/**
* 堆最大大小
*/
private int maxSize;
/**
* 堆当前大小
*/
private int currentSize;
/**
* 构造最小堆
*
* @param maxSize
*/
public MinHeap(int maxSize) {
this.maxSize = maxSize;
heapArray = new Node[maxSize];
currentSize = 0;
}
/**
* 自上而下扫描树,将节点换成两个子女中大的那一个
*
* @param start
* @param endOfHeap
*/
public void filterDown(int start, int endOfHeap) {
/**
*i当前节点
*/
int i = start;
/**
* 左边孩子节点
*/
int j = 2 * i + 1;
Node temp = heapArray[i];
//检查是否到达最后位置
while (j <= endOfHeap) {
//让j指向两子女中小的那一个
if (j < endOfHeap && heapArray[j].getIDate() > heapArray[j + 1].getIDate()) {
j++;
}
//如果子节点比当前点大则停止
if (temp.getIDate() <= heapArray[j].getIDate()) {
break;
}
//当前节点大,则交换i,j
else {
heapArray[i] = heapArray[j];
i = j;
j = 2 * j + 1;
}
}
//回送,即是将函数入口的开始值放到最后的位置,即底部位置
heapArray[i] = temp;
}
/**
* 自下而上的调整:从节点start开始到0为止,自下而上比较,如果子女的值小于双亲节点的值则互相交换
*
* @param start
*/
public void filterUp(int start) {
/**
*j 当前节点
*/
int j = start;
/**
* i 当前节点的双亲节点
*/
int i = (j - 1) / 2;
/**
* Node 暂存当前节点
*/
Node temp = heapArray[j];
//沿着双亲节点直达根节点
while (j > 0) {
//双亲节点值小,不调整
if (heapArray[i].getIDate() <= temp.getIDate()) {
break;
} else {
heapArray[j] = heapArray[i];
j = i;
i = (i - 1) / 2;
}
}
//回送,即是将函数入口的开始值放到最后的位置,即底部位置
heapArray[j] = temp;
}
/**
* 插入元素,根据当前关键字构建节点,自上而下扫瞄成功就插入,并且堆的大小加1
*
* @param key
* @return
*/
public boolean insert(int key) throws MinHeapException {
/**
* 为真则插入成功
*/
boolean bool = true;
//堆满插入失败
if (isFull()) {
bool = false;
throw new MinHeapException("heap is full");
} else {
/**
* 构建一个节点
*/
Node newNode = new Node(key);
//赋给最后的位置
heapArray[currentSize] = newNode;
//调整位置
filterUp(currentSize);
currentSize++;
}
return bool;
}
private boolean isFull() {
return currentSize == maxSize;
}
/**
* 按某种格式输出堆
*/
public void displayHeap() {
System.out.println("heapArray:");
for (int i = 0; i < currentSize; i++) {
if (heapArray[i] != null) {
System.out.println(heapArray[i].getIDate() + " ");
} else {
System.out.println("-- ");
}
}
System.out.println();
//输出堆
int nBlanks = 32;
int itemsPerRow = 1;
int column = 0;
int j = 0;
String dots = ".........................";
System.out.println(dots + dots);
while (currentSize > 0) {
if (column == 0) {
for (int k = 0; k < nBlanks; k++) {
System.out.print(" ");
}
}
System.out.print(heapArray[j].getIDate());
if (++j == currentSize) {
break;
}
if (++column == itemsPerRow) {
nBlanks /= 2;
itemsPerRow *= 2;
column = 0;
System.out.println();
} else {
for (int k = 0; k < nBlanks * 2 - 2; k++) {
System.out.print(" ");
}
}
}
System.out.println("\n" + dots + dots);
}
public boolean isEmpty() {
return currentSize == 0;
}
/**
* 删除最小元素,重新建立根节点
*/
public Node removeMin() throws MinHeapException {
if (isEmpty()) {
throw new MinHeapException("minHeap is empty");
}
/**
* 删除的节点
*/
Node root = heapArray[0];
//最后的节点移到最小的位置
heapArray[0] = heapArray[currentSize - 1];
currentSize--;
//将最小的位置的元素下沉
filterDown(0, currentSize - 1);
return root;
}
public void makeEmpty() {
currentSize = 0;
}
}
MinHeapApp
package com.example.taco.minHeapTest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* 最小堆测试
*
* @author lh
* @date 2022/01/13 20:01
*/
public class MinHeapApp {
public static void main(String[] args) throws IOException, MinHeapException {
int value1, value2;
MinHeap hp = new MinHeap(31);
boolean success;
hp.insert(23);
hp.insert(34);
hp.insert(3);
hp.insert(2233);
hp.insert(234);
hp.insert(21);
hp.insert(25);
hp.insert(25);
hp.insert(63);
while (true) {
System.out.println("enter first letter of ");
System.out.println("show,insert,remove:");
int choice = getChar();
switch (choice) {
case 's':
hp.displayHeap();
break;
case 'i':
System.out.println("enter value to insert:");
value1 = getInt();
success = hp.insert(value1);
if (!success) {
System.out.println("can't insert;heap is full");
}
break;
case 'r':
if (!hp.isEmpty()) {
hp.removeMin();
} else {
System.out.println("can't remove;heap is empty");
}
break;
default:
System.out.println("invalid enter\n ");
}
}
}
/**
* 获得控制台输入字符
*
* @return
* @throws IOException
*/
private static char getChar() throws IOException {
return getString().charAt(0);
}
/**
* 获得控制台输入流
*
* @return
* @throws IOException
*/
private static String getString() throws IOException {
return new BufferedReader(new InputStreamReader(System.in)).readLine();
}
/**
* 获得控制台输入的整形
*
* @return
* @throws IOException
* @throws NumberFormatException
*/
public static int getInt() throws IOException, NumberFormatException {
return Integer.parseInt(getString());
}
}
MinHeapException
package com.example.taco.minHeapTest;
/**
* @author lh
* @date 2022/01/14 0:14
*/
public class MinHeapException extends Exception{
private static final long serialVersionUID=1L;
public MinHeapException() {
super("MinHeapException");
}
public MinHeapException(String message) {
super(message);
}
}
Node
package com.example.taco.minHeapTest;
import lombok.Data;
/**
* 堆结点
* @author lh
* @date 2022/01/14 14:13
*/
@Data
public class Node {
/**
* 数据
*/
private int iDate;
public Node(int iDate){
super();
this.iDate=iDate;
}
}
输出堆