堆的数组实现
用数组来实现堆比链式实现简单,这是因为:
1)在插入操作中,链式实现需要一个getInsertNode方法去找插入在哪个结点之下,而在数组中,插入结点的位置下标是依次递增的,(完全二叉树)
插入操作的向上调整也可以直接根据下标来找父节点(思维和链式一样)
2)在删除堆顶的操作中,链式实现把lastNode的值赋给堆顶后,还要去找倒数第二个结点来更新lastNode,而在数组里就不需要,直接根据下标就知道哪个是倒数第二个结点,而且也不需要记录lastNode。
删除操作的自上往下调整,左右子节点也可以通过下标来定,这个思路和链式一样,也是用递归,只是改为了下标来移动
经过上面的比较和分析,数组怎么去实现已经很清楚了,下面简要介绍:
1,实例变量,构造方法,数组扩展
private Comparable[] contents;
private int count; //count不仅表示大小,还表示下一个存储位置,注意堆是一棵完全二叉树
public ArrayHeap()
{
contents = new Comparable[10];
count = 0;
}
public ArrayHeap(Comparable ele)
{
contents = new Comparable[10];
contents[0] = ele;
count = 1;
}
public void expand()
{
Comparable[] larger = new Comparable[contents.length*3];
for(int i =0;i < size();i++)
larger[i] = contents[i];
contents = larger;
}
2,插入操作
public void addElement(Comparable element) {
// TODO Auto-generated method stub
if(size() == contents.length)
expand();
contents[count] = element; //插入位置已知
count++;
upAdjustHeap(); //自底向顶调整堆
}
自底向上调整过程:
private void upAdjustHeap(){
int index = count - 1; //最后一个元素下标
while(index != 0)
{
if(index % 2 == 0) //如果是右节点
{
int pindex = (index - 2)/2;
if(contents[index].compareTo(contents[pindex]) < 0)
{
Comparable temp = contents[index];
contents[index] = contents[pindex];
contents[pindex] = temp;
index = pindex;
}
else break;
}
else //是左节点
{
int pindex = (index - 1)/2;
if(contents[index].compareTo(contents[pindex]) < 0)
{
Comparable temp = contents[index];
contents[index] = contents[pindex];
contents[pindex] = temp;
index = pindex;
}
else break;
}
}
}
3,删除操作
public Comparable removeMin() {
// TODO Auto-generated method stub
if(size() == 0)
{
System.out.println("堆为空");
return null;
}
Comparable result = contents[0];
contents[0] = contents[count-1];
contents[count-1] = null;
count--;
downAdjustHeap(0); //递归的函数,调整以下标0为根的堆
return result;
}
自顶向下调整的过程跟链式差不多,思路都一样,只是换成了数组
private void downAdjustHeap(int index){//自顶往下调整以index下标为根的树
int lindex = 2 * index + 1;
int rindex = 2 * index + 2;
if(contents[lindex] != null && contents[rindex] != null)
{
if(contents[lindex].compareTo(contents[rindex]) < 0)
{
if(contents[lindex].compareTo(contents[index]) < 0)
{
Comparable temp = contents[index];
contents[index] = contents[lindex];
contents[lindex] = temp;
downAdjustHeap(lindex);
}
else return;
}
else
{
if(contents[rindex].compareTo(contents[index]) < 0)
{
Comparable temp = contents[index];
contents[index] = contents[rindex];
contents[rindex] = temp;
downAdjustHeap(rindex);
}
else return;
}
}
else if(contents[lindex] != null && contents[rindex] == null)
{
if(contents[lindex].compareTo(contents[index]) < 0)
{
Comparable temp = contents[index];
contents[index] = contents[lindex];
contents[lindex] = temp;
downAdjustHeap(lindex);//直接return也可
}
else return;
}
else
return;
}
4,完整清单及测试:
ArrayHeap
package Heap;
import java.util.Iterator;
import Queue.LinkedQueue;
public class ArrayHeap implements HeapADT {
private Comparable[] contents;
private int count; //count不仅表示大小,还表示下一个存储位置,注意堆是一棵完全二叉树
public ArrayHeap()
{
contents = new Comparable[10];
count = 0;
}
public ArrayHeap(Comparable ele)
{
contents = new Comparable[10];
contents[0] = ele;
count = 1;
}
public void expand()
{
Comparable[] larger = new Comparable[contents.length*3];
for(int i =0;i < size();i++)
larger[i] = contents[i];
contents = larger;
}
//堆的重要的方法
public void addElement(Comparable element) {
// TODO Auto-generated method stub
if(size() == contents.length)
expand();
contents[count] = element; //插入位置已知
count++;
upAdjustHeap(); //自底向顶调整堆
}
private void upAdjustHeap(){
int index = count - 1; //最后一个元素下标
while(index != 0)
{
if(index % 2 == 0) //如果是右节点
{
int pindex = (index - 2)/2;
if(contents[index].compareTo(contents[pindex]) < 0)
{
Comparable temp = contents[index];
contents[index] = contents[pindex];
contents[pindex] = temp;
index = pindex;
}
else break;
}
else //是左节点
{
int pindex = (index - 1)/2;
if(contents[index].compareTo(contents[pindex]) < 0)
{
Comparable temp = contents[index];
contents[index] = contents[pindex];
contents[pindex] = temp;
index = pindex;
}
else break;
}
}
}
public Comparable removeMin() {
// TODO Auto-generated method stub
if(size() == 0)
{
System.out.println("堆为空");
return null;
}
Comparable result = contents[0];
contents[0] = contents[count-1];
contents[count-1] = null;
count--;
downAdjustHeap(0); //递归的函数,调整以下标0为根的堆
return result;
}
private void downAdjustHeap(int index){//自顶往下调整以index下标为根的树
int lindex = 2 * index + 1;
int rindex = 2 * index + 2;
if(contents[lindex] != null && contents[rindex] != null)
{
if(contents[lindex].compareTo(contents[rindex]) < 0)
{
if(contents[lindex].compareTo(contents[index]) < 0)
{
Comparable temp = contents[index];
contents[index] = contents[lindex];
contents[lindex] = temp;
downAdjustHeap(lindex);
}
else return;
}
else
{
if(contents[rindex].compareTo(contents[index]) < 0)
{
Comparable temp = contents[index];
contents[index] = contents[rindex];
contents[rindex] = temp;
downAdjustHeap(rindex);
}
else return;
}
}
else if(contents[lindex] != null && contents[rindex] == null)
{
if(contents[lindex].compareTo(contents[index]) < 0)
{
Comparable temp = contents[index];
contents[index] = contents[lindex];
contents[lindex] = temp;
downAdjustHeap(lindex);//直接return也可
}
else return;
}
else
return;
}
public Comparable findMin() {
// TODO Auto-generated method stub
return contents[0];
}
//迭代器,跟二叉树的数组实现一样
public int size() {
return count;
}
public boolean isEmpty() {
return (size()==0);
}
public Iterator iteratorInorder() {
LinkedQueue queue = new LinkedQueue();
inorder(0,queue);
return queue.iterator();
}
private void inorder(int index,LinkedQueue queue){
if(index < contents.length && contents[index] != null)
{
int lindex = 2 * index + 1;
int rindex = 2 * index + 2;
if(lindex < contents.length && contents[lindex] != null)
inorder(lindex,queue);
queue.enqueue(contents[index]);
if(rindex < contents.length && contents[rindex] != null)
inorder(rindex,queue);
}
}
public Iterator PreInorder() {
LinkedQueue queue = new LinkedQueue();
preorder(0,queue);
return queue.iterator();
}
private void preorder(int index,LinkedQueue queue){
if(index < contents.length && contents[index] != null)
{
int lindex = 2 * index + 1;
int rindex = 2 * index + 2;
queue.enqueue(contents[index]);
if(lindex < contents.length && contents[lindex] != null)
preorder(lindex,queue);
if(rindex < contents.length && contents[rindex] != null)
preorder(rindex,queue);
}
}
public Iterator PostInorder() {
LinkedQueue queue = new LinkedQueue();
postorder(0,queue);
return queue.iterator();
}
private void postorder(int index,LinkedQueue queue){
if(index < contents.length && contents[index] != null)
{
int lindex = 2 * index + 1;
int rindex = 2 * index + 2;
if(lindex < contents.length && contents[lindex] != null)
postorder(lindex,queue);
if(rindex < contents.length && contents[rindex] != null)
postorder(rindex,queue);
queue.enqueue(contents[index]);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayHeap heap = new ArrayHeap();
heap.addElement(12);
heap.addElement(17);
heap.addElement(11);
heap.addElement(4);
heap.addElement(10);
heap.addElement(6);
heap.addElement(8);
heap.addElement(22);
heap.addElement(16);
heap.addElement(5);
heap.addElement(2);
heap.addElement(9);
heap.addElement(7);
heap.addElement(20);
heap.addElement(28);
heap.addElement(13);
heap.addElement(15);
System.out.println("堆的大小为: " + heap.size());
System.out.println("堆为空吗?: " + heap.isEmpty());
System.out.println("\n\n中序序列为: ");
Iterator it = heap.iteratorInorder();
while(it.hasNext())
System.out.print(it.next() + " ");
System.out.println("\n前序序列为: ");
it = heap.PreInorder();
while(it.hasNext())
System.out.print(it.next() + " ");
System.out.println("\n后序序列为: ");
it = heap.PostInorder();
while(it.hasNext())
System.out.print(it.next() + " ");
heap.removeMin();
System.out.println("\n\n\n删除最小值后前序序列为: ");
it = heap.PreInorder();
while(it.hasNext())
System.out.print(it.next() + " ");
heap.removeMin();
System.out.println("\n接着删除最小值后前序序列为: ");
it = heap.PreInorder();
while(it.hasNext())
System.out.print(it.next() + " ");
heap.removeMin();
System.out.println("\n接着删除最小值后前序序列为: ");
it = heap.PreInorder();
while(it.hasNext())
System.out.print(it.next() + " ");
}
}
还是建的上一篇的堆:
结果:
堆的大小为: 17
堆为空吗?: false
中序序列为:
22 15 16 13 17 4 11 5 10 2 12 7 9 6 20 8 28
前序序列为:
2 4 13 15 22 16 17 5 11 10 6 7 12 9 8 20 28
后序序列为:
22 16 15 17 13 11 10 5 4 12 9 7 20 28 8 6 2
删除最小值后前序序列为:
4 5 13 15 22 17 10 11 16 6 7 12 9 8 20 28
接着删除最小值后前序序列为:
5 10 13 15 17 11 22 16 6 7 12 9 8 20 28
接着删除最小值后前序序列为:
6 10 13 15 17 11 22 16 7 9 12 28 8 20