Java堆结构
堆的特点
- 堆:堆是一种树,由它实现的优先级队列的插入和删除的时间复杂度都是O(logn),用堆实现的优先级队列虽然和数组实现相比较删除慢了些,但插入的时间快的多了。当速度很重要且有很多插入操作时,可以选择堆来实现优先级队列。
- Java的堆和数据结构堆:Java的堆是程序员用new能得到的计算机内存的可用部分。而数据结构的堆是一种特殊的二叉树。
- 堆是一个完全二叉树。什么叫完全二叉树?就是除了堆的最后一层节点外,其他层节点都是满的,完全二叉树如此有规律,以至于我们选择使用数组表示完全二叉树,而不是必须使用链:
堆的分类
- 小顶堆:所有节点的左右孩子节点都小于或者等于父节点。上图也是一个小顶堆。
- 大顶堆:所有节点的左右孩子节点都大于或者等于父节点。
堆的数据分布
堆中每一个节点都满足堆的条件,也就是说每一个关键字的值都大于或等于这个节点的子节点的关键字值。
堆是完全二叉树的事实说明了表示堆的数组中没有空项,即从0–>n-1的每个数据单元都有数据项。
堆的操作
- 移除根节点
说明:在被筛选节点的每个暂时停留的位置,向下筛选的算法总是要检查哪一个子节点更大,然后目标节点和较大的子节点交换位置,如果要把目标节点和较小的子节点交换,那么这个子节点就会变成大子节点的父节点,这就违背了堆的条件。
- 堆的插入
说明:向上筛选的算法比向下筛选的算法相对简单,因为它不需要比较两个子节点关键字值的大小,节点只有一个父节点。目标节点主要和它的父亲节点换位即可。
如果我们用数组表示一棵树时,节点的位置索引是X,则:
- 它的父节点的下标是:(x-1)/2;
- 它的左子节点的下标为2*x + 1;
- 它的右子节点的下标是2*x + 2;
代码
堆结构:
package com.wjb.day20210927;
/**
* @Classname Node
* @Description TODO
* @Date 2021/9/27 10:07
* @Created by wjb
*/
public class Node {
private int value;
public Node(int id){
value = id;
}
public int getKey(){
return value;
}
public void setKey(int value){
this.value = value;
}
}
堆的实现类:
package com.wjb.day20210927;
/**
* @Classname
* @Description 堆的实现类
* @Date 2021/9/27 10:07
* @Created by wjb
*/
public class Heap {
private Node[] heapArray; // 堆的存储空间
private int maxSize; // 堆大小
private int currentSize; // 当前索引值(当前操作所指位置)
public Heap(int mx){
maxSize = mx;
heapArray = new Node[maxSize];
currentSize = 0;
}
// 判断堆结构是否有数据
public boolean isEmpty(){
return currentSize == 0 ;
}
// 插入堆节点
public boolean insert(int key){
if (currentSize == maxSize)
return false;
Node thenode = new Node(key);
heapArray[currentSize] = thenode;
trickleUp(currentSize ++);
return true;
}
// 向上替换
public void trickleUp(int index){
int parent = (index - 1) / 2;
Node bottom = heapArray[index];
while (index > 0 && heapArray[parent].getKey() < bottom.getKey()){
heapArray[index] = heapArray[parent];
index = parent;
parent = (parent - 1) / 2;
}
heapArray[index] = bottom;
}
// 删除根节点
public Node remove(){
Node root = heapArray[0];
heapArray[0] = heapArray[-- currentSize];
trickleDown(0);
return root;
}
// 向下替换
public void trickleDown(int index){
int largeChild;
Node top = heapArray[index];
while (index < currentSize / 2){
int leftChild = 2 * index + 1;
int rightChild = 2 * index + 2;
if (rightChild < currentSize && heapArray[leftChild].getKey() < heapArray[rightChild].getKey())
largeChild = rightChild;
else
largeChild = leftChild;
if (top.getKey() >= heapArray[largeChild].getKey())
break;
heapArray[index] = heapArray[largeChild];
index = largeChild;
}
heapArray[index] = top;
}
// 改变节点值
public boolean change(int index,int newvalue){
if (index < 0 || index >=currentSize)
return false;
int oldvalue = heapArray[index].getKey();
heapArray[index].setKey(newvalue);
if (oldvalue < newvalue)
trickleUp(index);
else
trickleDown(index);
return true;
}
// 输出堆结构 桉树的方式打印
public void displayHeap(){
System.out.print("heapArray:");
for (int i = 0; i < currentSize; i++) {
if (heapArray[i] != null)
System.out.print(heapArray[i].getKey()+" ");
else
System.out.print("--");
}
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 i = 0; i < nBlanks; i++) {
System.out.print(" ");
}
System.out.print(heapArray[j].getKey());
if (++ j == currentSize)
break;
if (++ column == itemsPerrow){
nBlanks /= 2;
itemsPerrow *= 2;
column = 0;
System.out.println();
}
else
for (int i = 0; i < nBlanks * 2 - 2; i++)
System.out.print(' ');
}
System.out.println("\n"+dots + dots);
}
// 输出堆结构组中的数据
public void displayArray(){
for (int i = 0; i < maxSize; i++)
System.out.print(heapArray[i].getKey()+" ");
System.out.println();
}
//根据下表插入节点
public void insertAt(int index,Node newnode){
heapArray[index] = newnode;
}
// 对结构索引加一
public void incrementSize(){
currentSize ++;
}
}
Test:
package com.wjb.day20210927;
import java.util.Scanner;
/**
* @Classname TestHeap
* @Description 测试堆结构
* @Date 2021/9/27 10:10
* @Created by wjb
*/
public class TestHeap {
public static void main(String[] args) {
// Heap h = new Heap(10);
// h.insert(34);
// h.insert(30);
// h.insert(22);
// h.insert(16);
// h.insert(14);
// h.insert(5);
// h.insert(16);
// h.insert(10);
// h.insert(3);
// h.insert(45);
// h.displayHeap();
// h.remove();
// h.displayHeap();
//堆排序
int size;
Scanner in = new Scanner(System.in);
System.out.print("Enter number of items: ");
size = in.nextInt();
Heap theheap = new Heap(size);
// 生成随机数
for (int i = 0; i < size; i++) {
int random = (int)(Math.random()*100);
Node node = new Node(random);
theheap.insertAt(i, node);
theheap.incrementSize();
}
System.out.print("random: ");
theheap.displayArray();
// 排序
for (int i = size / 2 - 1; i >= 0; i --) {
theheap.trickleDown(i);
}
System.out.print("heap: ");
theheap.displayArray();
theheap.displayHeap();
//小顶堆
for (int i = size - 1; i >= 0; i --) {
Node node = theheap.remove();
theheap.insertAt(i,node);
}
System.out.print("sorted: ");
theheap.displayArray();
}
}
以上就是对Java中的堆结构一些简单的理解。更多操作还得自己去拓展。