数据结构堆
1.定义:
一类由完全二叉树组成的数组对象的数据结构。
2.特点:
①它是完全二叉树,除了树的最后一层结点无需点满,其他层数必须都是满的,如果最后一层不满,则必须要求左满右不满。
②该数据结构底层由数组实现。
3.图解:
4.规律:
①若一个索引为k,则父结点索引为k/2,子结点位置为2k或者2k+1。
②向上一层,则k = k/2;向下一层,则k = 2k或者k = 2k+1。
③每个结点都大于它的子结点。
5.堆的设计框架
6.代码实现
(1).属性
//数组储存T类型元素
private T[] items;
//堆的元素个数
private int N;
(2).构造方法
//构造方法
public Heap(int capacity) {
items = (T[]) new Comparable[capacity];
N = 0;
}
(3).功能方法
<1>.判断索引i处的元素是否小于索引j处元素
//判断索引i处的元素是否小于j处元素
public boolean less(int i, int j) {
return items[i].compareTo(items[j]) < 0;
}
<2>.交换索引i和索引j处元素
//交换索引i处与索引j处的元素
public void exchange(int i,int j){
T temp = items[i];
items[i] = items[j];
items[j] = temp;
}
<3>.向堆中插入元素t
//向堆中插入一个元素
public void insert(T t){
//在数组长度+1的位置添加,并且个数N+1
items[++N] = t;
//调用上浮算法,使k处元素处在正确位置
swim(N);
}
<4>.上浮算法
//上浮算法
public void swim(int k){
while(k>1){
//使索引为k的元素与父结点进行比较
//若前者较小,则结束循环
//若后者较小,则交换其位置
if (less(k,k/2)){
break;
}
exchange(k,k/2);
//更新新的k值
k = k/2;
}
}
<5>.删除堆中最大的元素,并返回该元素
//删除堆中最大元素,并返回
public T deleteMax(){
//用新变量记录原最大值,便于函数的返回值
T max = items[1];
//由于根结点最大,交换根结点与尾结点的元素
exchange(1,N);
//删除尾结点的元素
items[N] = null;
//使用下沉算法使新的根结点处于适合的位置
sink(1);
//元素个数-1
N--;
//返回删除的元素值
return max;
}
<6>.下沉算法
//下沉算法
public void sink(int k){
while (k*2 <= N){
//考虑子结点有左右结点的情况
//设置变量储存左右子结点的较大值索引
int bigIndex ;
if (k*2+1 <= N){
if (less(k*2,k*2+1)){
bigIndex = k*2+1;
}else{
bigIndex = k*2;
}
}
//子结点仅有左节点情况
else{
bigIndex = k*2;
}
if (less(bigIndex,k)){
break;
}
exchange(bigIndex,k);
//变换k的值
k = bigIndex;
}
}
7.堆的应用
(1).堆排序
<1>.设计框架
<2>.代码实现
a.判断heap堆中索引i处元素是否小于索引j处元素
//判断Heap堆中元素索引i处元素是否小于索引j处的元素
private static boolean less(Comparable[] heap,int i,int j){
return heap[i].compareTo(heap[j])<0;
}
b.交换heap堆中索引i处元素与索引j处元素
//交换堆中索引i与索引j处的元素
private static void exchange(Comparable[] heap,int i,int j){
Comparable temp = heap[i];
heap[i] = heap[j];
heap[j] = temp;
}
c.根据待排序数组source,构造出堆heap
//根据原数组source,构建出堆heap
private static void createHeap(Comparable[] source,Comparable[] heap){
//调用System下的ArrayCopy方法将source数组拷贝到heap数组中形成无序堆
System.arraycopy(source,0,heap,1,source.length);
//对新的无序堆中元素进行循环下沉操作(从数组长度一半开始,向1扫描),使其有序
for (int i = heap.length/2;i > 0;i--){
sink(heap,i,heap.length-1);
}
}
d.对source数组中元素从小到大排序
//对source中的元素从小到大排序
public static void sort(Comparable[] source){
//构建堆
Comparable[] heap = new Comparable[source.length+1];
createHeap(source,heap);
//定义一个变量,记录未排序数组中的最大索引
int N = heap.length-1;
while(N != 1){
//交换索引1处的元素与未排序的最大索引处元素
exchange(heap,1,N);
//变换N的值,使其不在参与下一轮排序
N--;
//下沉算法,使索引1处的新元素就位
sink(heap,1,N);
}
//将heap中的元素拷贝到原数组source中即排序成功
System.arraycopy(heap,1,source,0,source.length);
}
e.在堆heap中,在0-range范围内堆target结点做下沉算法
//在heap中,对target下沉算法,范围是0-range
private static void sink(Comparable[] heap,int target,int range){
while(target*2<=range){
//当左右结点都存在的时候,找出元素最大值对应下标
int bigIndex;
if (target*2+1<=range){
//比较左右结点元素大小
if (less(heap,target*2,target*2+1)){
bigIndex = target*2+1;
}else{
bigIndex = target*2;
}
}
//当仅存在左结点时
else{
bigIndex = target*2;
}
//比较目标节点target与找到的子结点较大值
if (!less(heap,target,bigIndex)){
break;
}
//当target比子结点小时,交换元素
exchange(heap,target,bigIndex);
//变换target的值
target = bigIndex;
}
}
f.堆排序的测试
public class HeapSortTest {
public static void main(String[] args) {
//创建一个字符串数组sortexample
String[] str = {"S","O","R","T","E","X","A","M","P","L","E"};
//调用写好的堆排序方法
HeapSort.sort(str);
//打印输出结果
System.out.print(Arrays.toString(str));
}
}
输出结果:
[A, E, E, L, M, O, P, R, S, T, X]