二叉树的一个存储结构:
使用数组保存二叉树结构,方式即将二叉树用层序遍历方式放入数组中。
一般只适合表示完全二叉树,因为非完全二叉树会有空间的浪费。
这种方式的主要用法就是堆的表示。
下标的一个关系
已知双亲(parent)的下标,则:
左孩子(left)下标 = 2 * parent + 1; 右孩子(right)下标 = 2 * parent + 2;
已知孩子(不区分左右)(child)下标,则:
双亲(parent)下标 = (child - 1) / 2;
堆的一个概念
- 堆逻辑上是一棵完全二叉树
- 堆物理上是保存在数组中
- 满足任意结点的值都大于其子树中结点的值,叫做大堆,或者大根堆,或者大堆
- 反之,则是小堆,或者小根堆,或者小堆
- 堆的基本作用是,快速找集合中的最值
我们是建造一个大堆
因为我们是由数组实现的我们先来将它的属性完善
import java.util.Arrays;
public class TestHeap {
public int[] elem;
public int usedSize;
public TestHeap() {
this.elem = new int[20];
this.usedSize = 0;
}
我们现在要做的第一步是需要将使用我们的数组建造一个大堆
public void adjustDown(int root, int len) {
//向下调整
int parent = root;
int child = 2 * parent + 1;
while (child < len) {
if (child + 1 < len && elem[child] < elem[child + 1]) {
child = child + 1;
}
if (elem[child] > elem[parent]) {
int tmp = elem[child];
elem[child] = elem[parent];
elem[parent] = tmp;
parent = child;
child = 2 * parent + 1;
} else {
break;
}
}
}
public void createHeap(int[] array) {
for (int i = 0; i < array.length; i++) {
this.elem[i] = array[i];
this.usedSize++;
}
for (int i = (this.usedSize - 1 - 1) / 2; i >= 0; i--) {
//我们以层序遍历实现 现在调用向下转型就可以建造为大堆
adjustDown(i, this.usedSize);
}
}
现在大堆已经建造好了,我们现在进行插入val
public void adjustUp(int child) {
//向上调整 此基础必须保证我们现在已经是一个堆
while (child > 0) {
int parent = (child - 1) / 2;
if (this.elem[child] > this.elem[parent]) {
int tmp = this.elem[child];
this.elem[child] = this.elem[parent];
this.elem[parent] = tmp;
child = parent;
parent = (child - 1) / 2;
} else {
break;
}
}
}
public boolean isFull(){
return this.usedSize==this.elem.length;
}
public void pushHeap(int val){
//想要插入元素我们在此之前是需要先判断我们现在数组是否是慢的状态
if (isFull()){
//扩容
this.elem=Arrays.copyOf(this.elem, this.elem.length*2);
}
this.elem[usedSize]=val;
this.usedSize++;
//判断完我们现在进行向上调整保证我们插入值后是一个大堆树
adjustUp(this.usedSize-1);
}
我们现在进行将我们最大值pop出去
public boolean isEmpty(){
return this.usedSize==0;
}
public void popHeap(){
//此时需要判断我们是不是为空
if (isEmpty()){
return;
}
int tmp=this.elem[0];
this.elem[0]=this.elem[this.usedSize-1];
this.elem[this.usedSize-1]=tmp;
this.usedSize--;
//我们现在是少了一个有效值需要再次调用我们的向下调整来构造为大堆树
adjustDown(0, this.usedSize);
}
现在获取最大值操作
public int getPop(){
//还是先判断我们是否为空
if (isEmpty()){
return -1;
}else {
return this.elem[0];
}
}
完成这些操作 我们是需要写一个打印的函数进行打印他们的值
public void display(){
for (int i = 0; i <this.usedSize ; i++) {
System.out.print(this.elem[i]+" ");
}
System.out.println();
}
提供我们main函数
public class TestDemo {
public static void main(String[] args) {
int []array={13,8,2,7,10,9,11,15,12,6};
TestHeap testHeap=new TestHeap();
testHeap.createHeap(array);
testHeap.display();
testHeap.pushHeap(14);
testHeap.display();
testHeap.popHeap();
testHeap.display();
int c=testHeap.getPop();
System.out.println(c);
}
}