最大堆
1.堆:是一个可以被看成一棵树的数组对象,满足如下要求:
a:堆中的父亲结点(优先级)总是大于等于孩子结点;
b:必须是一棵完全二叉树(叶子结点的高度差不能超过1,除过树的最后一层,树的其它层必须是满二叉树,按层依次进行排列,组成一颗二叉树)。
2.根据堆的性质可以得出以下结论:
- 根结点没有父亲结点;
- 除根结点之外的任意结点(i)的父亲结点的索引为:parent = i/2(根结点从1开始)或parent = (i-1)/2(根结点从0开始);
- 任意结点(i)的左孩子结点的索引为:leftIndex = i2(根结点从1开始)或leftIndex = i2+1(根结点从0开始);
- 任意结点(i)的右孩子结点的索引为:rightIndex = i2+1(根结点从1开始)或rightIndex = i2+2(根结点从0开始)。
3.代码实现
package com.ff.数据结构.myheap;
import java.util.Arrays;
/**
* 最大堆:
* 1.是一颗完全二叉树;
* 2.父亲结点(优先级)总是大于等于孩子结点
*/
public class MaxHeap<T extends Comparable<T>> {
private T[] data; //数据容器,保存完全二叉树中结点的内容
private int size; //保存树中元素个数
public MaxHeap(){
data = (T[])new Comparable[50];
size = 0;
}
//判断树是否为空
public boolean isEmpty(){
return this.size == 0;
}
//获取树中元素个数
public int getSize(){
return this.size;
}
//获取数据
public T[] getData(){
return this.data;
}
//向最大堆的这棵树中添加元素
public void add(T ele){
data[size] = ele;
size++;
//上浮操作
floatUp(size-1);
//方法2
//floatUp2(size-1,ele);
}
private void floatUp(int index){
//获取父亲结点的索引
int parentIndex = (index-1)/2;
//进行比较
while (index > 0 && data[parentIndex].compareTo(data[index])<0){
swap(data,parentIndex,index);
index = parentIndex;
parentIndex = (index - 1)/2;
}
}
private void floatUp2(int index,T ele){
//获取父亲结点
int parentIndex = (index - 1)/2;
while (index>0 && data[parentIndex].compareTo(ele)<0){
data[index] = data[parentIndex];
index = parentIndex;
parentIndex = (index - 1)/2;
}
data[index] = ele;
}
//取出优先级最高的元素
public T removeEle() throws IllegalAccessException {
if(isEmpty()){
throw new IllegalAccessException("the maxHeap is empty!");
}
T ele = data[0];
//下沉操作
swim();
return ele;
}
private void swim(){
data[0] = data[size-1];
size--;
//当前结点
int currentIndex = 0;
int leftIndex = currentIndex * 2 + 1;
int changeIndex = leftIndex;
//找到左右子树优先权最高的结点
while (leftIndex<size){
if(leftIndex+1<size && data[leftIndex+1].compareTo(data[leftIndex])>0){
changeIndex+=1;
}
if(data[currentIndex].compareTo(data[changeIndex])<0){
//交换操作
swap(data,currentIndex,changeIndex);
currentIndex = changeIndex;
leftIndex = currentIndex*2+1;
changeIndex = leftIndex;
}else {
break;
}
}
}
//替换优先级最高的元素
public void replace(T newValue) throws IllegalAccessException {
if(isEmpty()){
throw new IllegalAccessException("the maxHeap is empty!");
}
swim(newValue);
}
private void swim(T newValue){
data[0] = newValue;
int currentIndex = 0;
int leftIndex = currentIndex*2 + 1;
int changeIndex = leftIndex;
while (leftIndex<size){
if(leftIndex+1<size && data[leftIndex+1].compareTo(data[leftIndex])>0){
changeIndex += 1;
}
if(data[currentIndex].compareTo(data[changeIndex])<0){
swap(data,changeIndex,currentIndex);
currentIndex = changeIndex;
leftIndex = currentIndex*2 + 1;
changeIndex = leftIndex;
}else {
break;
}
}
}
//将任意数组整理成堆
public void heapify(T[] arr) throws IllegalAccessException {
if(arr == null || arr.length == 0){
throw new IllegalAccessException("the array is empty!");
}
//从最后一个结点的父结点开始做下沉操作
int adjustIndex = (arr.length - 1 - 1)/2;
for(;adjustIndex>=0;adjustIndex--){
swim(arr,adjustIndex,arr.length);
}
}
private void swim(T[] arr,int index,int lenght){
int currentIndex = index;
int leftIndex = currentIndex*2 + 1;
int changeIndex = leftIndex;
while (leftIndex<lenght){
if(leftIndex+1<lenght && arr[leftIndex+1].compareTo(arr[leftIndex])>0){
changeIndex += 1;
}
if(arr[changeIndex].compareTo(arr[currentIndex])>0){
swap(arr,changeIndex,currentIndex);
currentIndex = changeIndex;
leftIndex = currentIndex*2 + 1;
changeIndex = leftIndex;
}
}
}
//辅助方法(交换操作)
private void swap(T[] arr,int parentIndex,int index){
T temp = arr[parentIndex];
arr[parentIndex] = arr[index];
arr[index] = temp;
/*arr[index] = arr[index] - arr[parentIndex];
arr[parentIndex] = arr[parentIndex] + arr[index];
arr[index] = arr[parentIndex] - arr[index];*/
}
@Override
public String toString(){
StringBuffer sb = new StringBuffer();
for(int i=0;i<size;i++){
sb.append(data[i] + ",");
}
return sb.substring(0,sb.lastIndexOf(",")).toString();
}
public static void main(String[] args) throws IllegalAccessException {
MaxHeap<Integer> maxHeap = new MaxHeap<>();
Integer[] arr = {1,34,6,23,56,66,43};
for(int i=0;i<arr.length;i++){
maxHeap.add(arr[i]);
}
System.out.println(maxHeap);
System.out.println(maxHeap.getSize());
maxHeap.removeEle();
System.out.println(maxHeap);
System.out.println(maxHeap.getSize());
maxHeap.replace(33);
System.out.println(maxHeap);
System.out.println(maxHeap.getSize());
Integer[] arr1 = {2,4,23,76,32,44,45};
MaxHeap<Integer> maxHeap1 = new MaxHeap<>();
maxHeap1.heapify(arr1);
System.out.println(Arrays.toString(arr1));
//System.out.println(maxHeap1.getSize());
}
}
优先队列
1.优先队列:出队顺序和入队顺序无关,和优先级有关,当访问元素时,优先级最高的会被删除,可以使用堆这种数据结构作为优先队列的底层结构。
2.代码实现
利用堆作为数据容器
package com.ff.数据结构.myheap;
import com.ff.数据结构.stackandqueue.Queue;
public class priorityQueue<T extends Comparable<T>> implements Queue<T> {
private MaxHeap<T> maxHeap;
@Override
public void enqueue(T ele) throws IllegalAccessException {
maxHeap.add(ele);
}
@Override
public T dequeue() throws IllegalAccessException {
return maxHeap.removeEle();
}
@Override
public T getFront() throws IllegalAccessException {
return maxHeap.getData()[0];
}
@Override
public boolean isEmpty() {
return maxHeap.isEmpty();
}
@Override
public int getSize() {
return maxHeap.getSize();
}
}