1.二叉树的存储
一种存储是顺序存储结构,另一种是链式存储结构。顺序存储结构仅适用于完全二叉树的存储,就是把完全二叉树从上到下、从左到右的顺序存储到一块连续的存储空间中,(可以理解为以层序遍历的顺序存储),其一般存储在一维数组中。
树是一种非线性结构,为了存储树,不仅需要存储树中各个结点本身的数据信息,还要能唯一地反映树中各个结点之间的逻辑关系。双亲表示法是树的一种顺序存储结构,这种表示法是用一维数组来存储树的相关信息,将树中的结点按照从上到下,从左到右的顺序存放在一个一维数组中,每个元素中存放一个结点的信息,包括该点本身的信息、该点双亲的位置,也就是双亲的下标。
二叉树的存储可以用一维数组实现,即将完全二叉树上标号为i的结点元素存储在一维数组下标为i的元素中。按照层序的方式把值平铺在数组中,关注数组下标的变化可以推导出:
已知双亲结点下标:left=2*parent+1;right=2*parent+2。
已知孩子结点下标:parent=(child-1)/2 取整。
2.堆
(1)堆的定义
堆通常是一个可以看做一棵完全二叉树的数组对象。可以说堆在逻辑上是一棵完全二叉树,在物理上是一维数组。
(2)堆的性质
- 堆总是一棵完全二叉树。
- 将根结点最大的堆叫做最大堆,根节点最小的堆叫做最小堆。
满足任意位置的值>=它的左右孩子的值,为大堆;满足任意位置的值<=它的左右孩子的值,为小堆。
所以堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。
- 常见堆有二叉堆等。
- 堆是非线性结构,相当于一维数组,有两个直接后继。
(3)堆的基本功能
找最值
(4)堆的操作
堆化(向上调整、向下调整)
堆化的前提:在整个堆中,除了要调整的位置之外,其余位置都已经满足堆的性质。
向上调整:让调整的结点与其孩子结点进行比较
向上调整:让调整的结点与其父亲结点进行比较
堆化思路:<以大堆为例>
- 如果要调整的位置是叶子节点,调整结束。
- 找到两个孩子中最大的一个孩子。(3种情况)只有左孩子;左右都有左孩子大;左右都有右孩子大
- 比较最大孩子的值和要调整位置的值,如果满足堆的性质了,调整结束,否则,交换两个值,继续调整原来最大孩子的下标位置。
建堆(任意数组转成堆)
建堆思路:从最后一个非叶子节点(最后一个节点的双亲节点),向下调整
最后一个非叶子节点:(size-2)/2
最后一个叶子节点:size-1
(5)堆的应用
- 优先级队列问题
- TopK问题
- 利用堆的特性做堆排序
代码实现:
import java.util.Arrays;
public class Heaps {//Heaps堆
/**
* 前提:除了index和它的孩子外,其他位置已经满足堆的性质了
* 经过向下调整(堆化),最终完全成为一个堆
* 时间复杂度是O(log(n))
* @param array 被看作堆的数组
* @param size 数组中被看作堆的值的个数
* @param index 要调整位置的下标
*/
//堆化为大堆
//堆化(向下调整)
public static void heapify(int[] array,int size,int index){
while(true){
int left = 2 * index + 1;
if (left >= size) {
return;
}
int max = left;
//找出孩子结点中最大的结点下标
if (left + 1 < size && array[left + 1] > array[left]) {//找最大
max = left + 1;
}
//比较该根结点与最大的孩子结点的大小,如果孩子结点大,则换位置
if (array[index] >= array[max]) {//比较
return;
}
swap(array,index, max);//交换
index = max;
}
}
//堆化(向上调整)
public static void adjustUp(int[] array,int index){
//向上调整到下标为0的位置就不调整了
if(index==0) {
return;
}
int parent=(index-1)/2;
//与父亲结点相比较
//如果父亲结点的值小,就交换位置,否则就不调整
if(array[index]>array[parent]){
return;
}
swap(array,index,parent);
index=parent;
}
public static void swap(int[]array,int i,int j){
int t = array[i];
array[i] = array[j];
array[j] = t;
}
//【建堆】
public static void createHeap(int[]array,int size){
for(int i=(size-2)/2;i>=0;i--){
heapify(array,size,i);
}
}
public static void main(String[] args){
int[]array={-1,8,4,6,7,2,3,1,0};
System.out.println("堆化");
heapify(array,array.length,0);
System.out.println(Arrays.toString(array));
adjustUp(array,0);
System.out.println(Arrays.toString(array));
System.out.println("建堆");
createHeap(array,array.length);
System.out.println(Arrays.toString(array));
}
}