数据结构之堆(java)

   记得以前已经实现过堆结构的一些操作,现在看看总有些不和谐,最近在看了看数据结构,觉得还是写的清晰具体一些,也可以方便以后的复习。下面介绍一下堆存在的一些意义。

   优先级队列可以用于计算机中的任务调度,在计算机中某些程序和活动需要比其他程序和活动先执行,因此需要给他们分配更高的优先级。

   另一个例子是在武器系统中,比如在一个海军巡洋舰系统中。会探测到许多对巡洋舰的威胁,比如来自飞机、导弹、潜水艇的攻击,需要为这些威胁分优先级。例如,离巡洋舰距离近的导弹就比距离远的飞机的优先级更高,这样对应的防范系统(例如地对空导弹)会首先对付它。

   堆是一种树,由它实现的优先级队列的插入和删除的时间复杂度是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)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值