要实现插入和查找操作,可以用队列。普通的队列,先入先出,那么对于插入insert操作,是常数级的时间复杂度;而对于查找操作,则需要遍历整个队列,需要时间O(n);我们也可以在插入时保证队列的有序,那么插入操作的时间复杂度为O(n),而查找操作则是O(1)。
也可以用二叉查找树实现容器,进行插入和查找操作,时间复杂度均为O(lgn)。但是如果输入本身有序,会导致二叉查找树的深度急剧增大。而二叉平衡树AVL的实现代价又太大,插入和删除均需旋转以保证树的平衡,实现比较复杂。
那么,另外一种数据结构就是堆。对于堆,我们可以看做一颗完全二叉树。故对于节点i,它的左孩子序号为2*i,右孩子序号为2*i+1。由于这样的特性,所以我们可以简单的仅用数组即可以实现堆。
以下就是用JAVA语言实现小顶堆的JAVA代码,其中在删除节点时,每次都将其调整为小顶堆,从而保证输出是有序队列,非常方便。
package com.Algorithm.Heap;
/*
* author:Tammy Pi
* function:二叉堆,本代码实现的是小顶堆
*/
public class BinaryHeap {
//存放元素的数组
//由于堆相当于一颗完全二叉树
//对于节点i,其左孩子为2*i,而右孩子为2*i+1,故可以简单通过数组实现
private int[] n=new int[101];
private int currentSize=0;
//小顶堆插入数字
public void insert(int i)
{
int hole=++currentSize;
if(hole==1)
{
n[hole]=i;
return;
}
for(;hole>1&&i<n[hole/2];hole=hole/2)
{
n[hole]=n[hole/2];
}
n[hole]=i;
}
//删除最小值
public int deleteMin()
{
int temp=n[1];
//首先用堆的最后一个元素取代它
//堆中元素从1到currentSize
n[1]=n[currentSize--];
adjustDown(1);
return temp;
}
public void adjustDown(int i)
{
int child;
int hold=i;
//调整后的最顶端
int temp=n[1];
for(;hold*2<=currentSize;hold=hold*2)
{
child=2*hold;
if(child+1<=currentSize&&n[child+1]<n[child])
{
child++;
}
if(n[child]<n[hold])
{
int temp1=n[hold];
n[hold]=n[child];
n[child]=temp1;
}
else
{
break;
}
}
n[currentSize+1]=temp;
}
public int[] getN() {
return n;
}
public void setN(int[] n) {
this.n = n;
}
public int getCurrentSize() {
return currentSize;
}
public void setCurrentSize(int currentSize) {
this.currentSize = currentSize;
}
//输出
public static void main(String[] args)
{
BinaryHeap heap=new BinaryHeap();
heap.insert(3);
heap.insert(1);
heap.insert(2);
heap.insert(1);
heap.insert(2);
for(int i=0;i<5;i++)
{
System.out.print(heap.deleteMin()+" ");
}
}
}