最大堆java_最大堆的Java实现

这里是整理后的代码:

import java.util.ArrayList;

import java.util.Arrays;

import java.util.Comparator;

import java.util.List;

import com.dm.core.structure.tupler.StrDoubleTuple;

/**

* 最大堆,用作优先队列的TOPK查找

* 原理:每个节点的值都>=其左右孩子(如果有的话)值的完全二叉树

*

* @author Anthony

* @param

*/

public class MaxHeap {

/**

* 堆数据

*/

private List heap;

/**

* 堆数据的比较对象

*/

private Comparator comparator;

public MaxHeap(List heap) {

this(heap, new Comparator() {

@SuppressWarnings("unchecked")

@Override

public int compare(T o1, T o2) {

return ((Comparable) o1).compareTo(o2);

}

});

}

public MaxHeap(List heap, Comparator comparator) {

super();

this.heap = heap;

this.comparator = comparator;

}

/**

* 向最大堆中插入元素,添加到数组的尾部,然后上升操作

*

* @param value

*/

public void insert(T value) {

// 数组下标为0的位置不放元素

if (heap.size() == 0)

heap.add(null);

heap.add(value);

up(heap.size() - 1);

}

/**

* 节点上升递归实现

* 由于新插入的数是在数组尾部,所以需要做上升操作,让插入的数和父节点的值比较,当大于父节点的时候交换

*

* @param index

*/

private void up(int index) {

// 注意堆是从下标为1开始,当index=1的时候,已经是根节点了

if (index <= 1)

return;

int parent = index / 2; // 父节点

T parentValue = heap.get(parent);

T indexValue = heap.get(index);

if (comparator.compare(parentValue, indexValue) < 0) {

swap(parent, index);

up(parent);

}

}

/**

* 节点上升非递归实现

*

* @param index

*/

@SuppressWarnings("unused")

private void up2(int index) {

int parent = 0;

for (; index > 1; index /= 2) {

parent = index / 2;

T parentValue = heap.get(parent);

T indexValue = heap.get(index);

if (comparator.compare(parentValue, indexValue) < 0)

swap(parent, index);

}

}

/**

* 交换a和b的位置

*

* @param a

* @param b

*/

private void swap(int a, int b) {

T temp = heap.get(a);

heap.set(a, heap.get(b));

heap.set(b, temp);

}

/**

* 删除堆中位置是index处的值

* 原理是:当删除节点时,原来的位置就会出现一个孔,填充这个孔的方法就是,把最后的叶子赋给该孔,然后把该叶子删除

*

* @param index

*/

public void delete(int index) {

heap.set(index, heap.get(heap.size() - 1));

down(index);

heap.remove(heap.size() - 1);

}

/**

* 节点下沉递归实现

* 删除数据的时候,由于是用的尾部的数据(基本上是最小值)填充,所以需要做下沉操作

*

* @param index

*/

public void down(int index) {

int n = heap.size() - 2; // 因为最后一个节点已经挪至index位置,所以已经是废弃叶子节点,不再考虑

int child = 2 * index;

// 说明该节点没有左右儿子节点了,那么无须下沉,直接返回

if (child > n)

return;

// 如果左右儿子都存在,取值较大的那个儿子节点

if (child < n

&& comparator.compare(heap.get(child), heap.get(child + 1)) < 0)

child++;

// 如果该节点小于较大的那个儿子,那么下沉

if (comparator.compare(heap.get(index), heap.get(child)) < 0) {

swap(child, index);

down(child);

}

}

/**

* 节点下沉非递归实现

*

* @param index

*/

public void down2(int index) {

T temp = heap.get(index);

int n = heap.size() - 2;

int child = 0;

for (; 2 * index <= n; index = child) {

child = 2 * index;

if (child < n

&& comparator.compare(heap.get(child), heap.get(child + 1)) < 0)

child++;

if (comparator.compare(temp, heap.get(child)) < 0)

swap(child, index);

else

break;

}

}

/**

* 根据树的性质建堆,树节点前一半一定是分支节点,即有孩子的,所以我们从这里开始调整出初始堆

*

* @param heap

*/

public void adjust() {

for (int i = heap.size() / 2; i > 0; i--)

adjust(i, heap.size() - 1);

}

/**

* 调整堆,使其满足最大堆得定义

* 具体调整过程为: 从最后一个分支结点(n/2)开始,到根(1)为止,依次对每个分支结点进行调整(下沉)

* 以便形成以每个分支结点为根的堆,当最后对树根结点进行调整后,整个树就变成了一个堆

*

* @param i

* @param n

*/

public void adjust(int i, int n) {

int child = 0;

for (; i <= n / 2;) {

child = i * 2;

if (child < n

&& comparator.compare(heap.get(child), heap.get(child + 1)) < 0)

child++;

if (comparator.compare(heap.get(i), heap.get(child)) < 0) {

swap(i, child);

i = child; // 交换后,以child+1为根的子树不一定满足堆定义,所以从child处开始调整

} else

break;

}

}

/**

* 堆排序,从尾部开始,将每个节点和根节点交换,然后调整节点之上的子堆

*/

public void sort() {

for (int i = heap.size() - 1; i > 0; i--) {

swap(1, i);

adjust(1, i - 1);

}

}

public static void main(String args[]) {

List array = new ArrayList(Arrays.asList(null, 1, 2,

5, 10, 3, 7, 11, 15, 17, 20, 9, 15, 8, 16));

MaxHeap mh = new MaxHeap(array);

mh.adjust();

System.out.println("调整后的初始堆:" + array);

mh.delete(8);

System.out.println("删除下标8之后的堆:" + array);

mh.insert(99);

System.out.println("添加值99之后的堆:" + array);

mh.sort();

System.out.println("排序后的堆:" + array);

List list = new ArrayList();

list.add(null);

list.add(new StrDoubleTuple("a", 1.0));

list.add(new StrDoubleTuple("a", 2.0));

list.add(new StrDoubleTuple("a", 5.0));

list.add(new StrDoubleTuple("a", 10.0));

list.add(new StrDoubleTuple("a", 3.0));

list.add(new StrDoubleTuple("a", 7.0));

list.add(new StrDoubleTuple("a", 11.0));

list.add(new StrDoubleTuple("a", 15.0));

list.add(new StrDoubleTuple("a", 17.0));

list.add(new StrDoubleTuple("a", 20.0));

list.add(new StrDoubleTuple("a", 9.0));

list.add(new StrDoubleTuple("b", 15.0));

list.add(new StrDoubleTuple("a", 8.0));

list.add(new StrDoubleTuple("a", 16.0));

MaxHeap mho = new MaxHeap(list);

mho.adjust();

System.out.println("调整后的初始堆:" + list);

mho.delete(8);

System.out.println("删除下标8之后的堆:" + list);

mho.insert(new StrDoubleTuple("a", 99.0));

System.out.println("添加值99之后的堆:" + list);

mho.sort();

System.out.println("排序后的堆:" + list);

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值