前两天在看Austern的Generic programming and STL,看到关于堆的操作,其中有个函数是is_heap,其复杂度是last - first +1,我没有仔细去看过STL的源代码,就自己想想STL的实现。
由于堆从逻辑上讲是一棵完全二叉树,因此自然而然就想到用递归。我就简单的写了下面的用递归判断堆的算法。
bool isheap2(int *arr, int pos, int size){
int child = pos * 2 + 1;
if (child < size){
if (arr[pos] < arr[child])return false;
if (isheap2(arr,child,size)){
child ++;
if (child < size){
if (arr[pos] < arr[child])return false;
return isheap2(arr,child,size);
}
}else{
return false;
}
}
return true;
}
但是仔细分析了一下,觉得STL的实现应该效率更高,我想不会用递归。就去VC 6看看,结果发现VC6中的STL居然没有is_heap,这简直是...,又去Linux下看看SGI的STL实现,发现确实STL的实现更高效。我就按照STL的实现写了个简单版本。
bool isheap(int *arr, int size){
int parent = 0;
for (int child = 1;child<size;++child){
if (arr[parent]<arr[child])
return false;
if ((child & 1) ==0)
++parent;
}
return true;
}
它利用堆的逻辑结构特点,通过(child & 1) ==0来判断当前节点是否为右儿子,如果是则说明当前parent的两个儿子都已经进行过比较,parent自增1指向下一个节点。
而且这里循环体中的自增都采用的是前缀自增,用前缀自增比后缀自增少进行一次内存的分配和对象的构造、析构和拷贝构造,效率更高。尤其是当数据量很大的时候,这会产生显著的效果。
从这个STL的算法其实我们可以扩展到n叉树,采用一种比较灵活的办法来获取其n个儿子。