记得以前已经实现过堆结构的一些操作,现在看看总有些不和谐,最近在看了看数据结构,觉得还是写的清晰具体一些,也可以方便以后的复习。下面介绍一下堆存在的一些意义。
优先级队列可以用于计算机中的任务调度,在计算机中某些程序和活动需要比其他程序和活动先执行,因此需要给他们分配更高的优先级。
另一个例子是在武器系统中,比如在一个海军巡洋舰系统中。会探测到许多对巡洋舰的威胁,比如来自飞机、导弹、潜水艇的攻击,需要为这些威胁分优先级。例如,离巡洋舰距离近的导弹就比距离远的飞机的优先级更高,这样对应的防范系统(例如地对空导弹)会首先对付它。
堆是一种树,由它实现的优先级队列的插入和删除的时间复杂度是O(logN).尽管这样删除的时间变慢了一点,但插入的时间快的多了。当速度非常重要,且有很多插入操作时,可以选择对来实现优先级队列。
堆可分为大根堆和小根堆,详细的概念就不多说了,为了大家可以真正的了解堆的原理,下面给出详细的代码。
/**
* @author Dylan
* @date 2015-11-25
* @see 堆的一个节点
* */
public class Node {
private int iData;
public Node(int key){
this.iData=key;
}
public int getKey(){
return iData;
}
<pre name="code" class="java">/**
* @author Dylan
* @date 2015-11-25
* @see 堆的相关操作
* */
public class Heap {
//该数组用于存储堆的节点
private Node[] heapArray;
//数据的存储大小
private int maxSize;
//当前数组中存储的节点
private int currentSize;
/**
* 初始化
* */
public Heap(int size){
maxSize=size;
heapArray=new Node[maxSize];
currentSize=0;
}
/**
* 判断是否为空
* */
public boolean isEmpty(){
return (currentSize==0);
}
/**
* 插入节点
* */
public boolean insert(int key){
if(currentSize==maxSize) //判断空间是否已满
return false;
Node newNode=new Node(key);
heapArray[currentSize]=newNode; //将新节点插入最后
trickleUp(currentSize++); //将节点向上调整
return true;
}
/**
* 向上筛选
* */
public void trickleUp(int index){
int parent=(index-1)/2;
Node bottom=heapArray[index]; //保存当前节点
while(index>0){
if(heapArray[parent].getKey()>bottom.getKey())
break;
else{
heapArray[index]=heapArray[parent];
index=parent;
parent=(parent-1)/2;
}
}
heapArray[index]=bottom;
}
/**
* 删除节点
* */
public Node remove(){
if(!isEmpty()){
Node root=heapArray[0];
heapArray[0]=heapArray[--currentSize];
trickleDown(0);
return root;
}
return null;
}
/**
* 向下过滤
* */
public void trickleDown(int index){
int largeChild,leftChild,rightChild;
Node top=heapArray[index];
while(index<currentSize/2){
leftChild=2*index+1;
rightChild=leftChild+1;
if(heapArray[leftChild].getKey()>heapArray[rightChild].getKey())
largeChild=leftChild;
else
largeChild=rightChild;
if(heapArray[largeChild].getKey()>heapArray[index].getKey())
heapArray[index]=heapArray[largeChild];
else
break;
index=largeChild;
}
heapArray[index]=top;
}
/**
* 用新数据替换旧的节点
* */
public boolean change(int index,int key){
if(index<0 || index>=currentSize)
return false;
int oldKey=heapArray[index].getKey();
heapArray[index].setKey(key);
if(oldKey>key)
trickleDown(index);
else
trickleUp(index);
return true;
}
/**
* 打印堆
* */
public void displayHeap(){
System.out.print("heapArray:");
for(int m=0;m<currentSize;m++){
if(heapArray[m]!=null)
System.out.print(heapArray[m].getKey()+" ");
}
System.out.println();
int column=0; //记录每行节点
int j=0; //记录已打印的节点
int nblank=32; //空格
int itemsPerRow=1; //每行的节点数
String dots="----------------------------------";
System.out.println(dots+dots);
while(currentSize>0){
if(column==0)
for(int k=0;k<nblank;k++){
System.out.print(" ");
}
System.out.print(heapArray[j].getKey());
//若所有的节点已打印,则跳出
if(++j==currentSize)
break;
if(++column == itemsPerRow){
System.out.println();
column=0;
itemsPerRow *=2;
nblank /=2;
}else{
for(int i=0;i<2*nblank-2;i++)
System.out.print(" ");
}
}
System.out.println();
System.out.println(dots+dots);
}
}
public void setKey(int key){this.iData=key;}} 上面的代码没有堆排序,其实看完上面的代码很容易会想到怎么对一个堆排序,这里就不写出来,留给读者自己完成,以便有一个更清晰的理解。
下面是测试代码:
public class HeapTest {
/**
* 读入字符串
* */
public static String getString(){
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader br=new BufferedReader(isr);
String str="";
try {
str=br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
/**
* 取字符串的第一个字符
* */
public static char getChar(){
String s=getString();
return s.charAt(0);
}
/**
* 输入数字
* */
public static int getInteger(){
String s=getString();
return Integer.parseInt(s);
}
public static void main(String[] args){
int value,value2;
Heap theHeap=new Heap(31);
boolean success;
theHeap.insert(70);
theHeap.insert(40);
theHeap.insert(50);
theHeap.insert(20);
theHeap.insert(60);
theHeap.insert(100);
theHeap.insert(80);
theHeap.insert(30);
theHeap.insert(10);
theHeap.insert(90);
theHeap.displayHeap();
while(true){
System.out.print("Enter first letter of : ");
System.out.println("show, insert, remove,change");
char choice=getChar();
switch(choice){
case 's':
theHeap.displayHeap();
break;
case 'i':
System.out.print("Enter value to insert:");
value=getInteger();
success=theHeap.insert(value);
if(!success)
System.out.println("Can't insert !");
break;
case 'r':
if(!theHeap.isEmpty())
theHeap.remove();
else
System.out.println("Can't remove !");
break;
case 'c':
System.out.print("Enter an index:");
value=getInteger();
System.out.print("Enter new key:");
value2=getInteger();
success=theHeap.change(value, value2);
if(!success){
System.out.println("Invalid index");
}
break;
default:break;
}
theHeap.displayHeap();
}
}
}
虽然没有写出堆排序的代码,但还是说一下堆排序的效率吧,尽管它比快速排序略慢,但它比快速排序优越的一点是它对初始数据的分布不敏感。在关键字值按某种排列顺序的情况下,快速排序运行的时间复杂度可以降低到O(N*N)级,然而堆排序对任意排列的数据,其排序的时间复杂度都是O(N*logN)