您的位置:首页 > 编程语言 > C语言/C++

二叉堆的c++模板类实现

2014-11-13 17:09 671 查看
我在http://blog.csdn.net/bdss58/article/details/40786355这篇博客中介绍了二叉堆的c语言实现。

这次,我将使用c++模板类技术实现这个二叉堆,使它能够存储更多的数据类型。也就是c++中的通用容器(generic collection)概念。

改写之后我们可以这样创建一个heap对象;

Heap<int, 32> h;


在C实现中,必须传递一个结构体实例的指针给函数,以便函数能够操作结构体中的数据。但是,c++可以面相对象,函数可以炒作类中的私有成员变量(将原结构体中的数据成员设计成c++的私有成员)。原来固定不变的堆最大容量max_size也可以设计到类的成员变量中。
而C中初始化函数可以设计到C++的构造函数中。
c++类中没有动态分配的变量,所以析构函数就不需要做什么了。
C实现中的那些辅助函数可以设计成c++ heap类的私有成员函数。而宏定义的函数,例如:
#define  LEFT_CHILD(index) (2 * (index) + 1)
#define RIGHT_CHILD(index) (2 * (index) + 2)


可以设计成inline函数,设计成内联函数的好处就是可以对参数进行类型检查。
下面是完整的实现代码:
/**
  * this file implemente binary heap data structure
  * using c++ template class
  * generic collection
  *
  * author by jianyong-lee
  * 2014/11/13
  * in southwest university
  *
  * lisence :GPL
  * */

#ifndef HEAP_TEMPLATE_H
#define HEAP_TEMPLATE_H

#include <assert.h>
#include <stdexcept>

template<typename T,int max_size>
class Heap
{
public:
    Heap();
    ~Heap();

    T get_first_value();
    void add_value(T value);

private:
    T values[max_size];
    int heap_size;

    void sift_down(int index);
    void sift_up(int index);
    void swap_value(int index_i,int index_j);

    inline int left_child(int index) {return 2*index+1;}
    inline int right_child(int index) {return 2*index+2;}
    inline int parent(int index) {return (index-1)/2;}
};

template<typename T,int max_size>
Heap<T,max_size>::Heap()
{
        heap_size=0;
}

template<typename T,int max_size>
Heap<T,max_size>::~Heap()
{

}

template<typename T,int max_size>
T Heap<T,max_size>::get_first_value()
{
    // assert(heap_size>0);
    if(heap_size<=0)
    {
        // throw "heap is empty!";
        throw std::underflow_error("heap is empty");
    }
    T result;
    result=values[0];
    heap_size--;
    if(heap_size!=0)
    {
        values[0]=values[heap_size];
        sift_down(0);
    }

    return result;
}

template<typename T,int max_size>
void Heap<T,max_size>::add_value(T value)
{
    // assert(heap_size<max_size);
    if(heap_size>max_size)
    {
        throw "heap is full";
    }
    values[heap_size]=value;
    heap_size++;
    if((heap_size-1)!=0)
    {
        sift_up(heap_size-1);
    }

}

template<typename T,int max_size>
void Heap<T,max_size>::sift_down(int index)
{
    int leftChild=left_child(index);
    int rightChild=right_child(index);
    if(leftChild>=heap_size)
    {
        return;
    }
    if(rightChild>=heap_size)
    {
        // only have left child
        if(values[leftChild]<values[index])
        {
            swap_value(index,leftChild);
            // don't need to call sift_down again
        }
    }
    else
    {
        if(values[leftChild]<values[index] || values[rightChild]<values[index])
        {
            if(values[leftChild]<values[rightChild])
            {
                swap_value(index,leftChild);
                sift_down(leftChild);
            }
            else
            {
                swap_value(index,rightChild);
                sift_down(rightChild);
            }
        }
    }

}

template<typename T,int max_size>
void Heap<T,max_size>::sift_up(int index)
{
    if(index==0) return;
    int parent_index=parent(index);
    assert(parent_index>=0);

    if(values[index]<values[parent_index])
    {
        swap_value(index,parent_index);
        if(parent_index!=0)
        {
            sift_up(parent_index);
        }
    }
}

template<typename T,int max_size>
void Heap<T,max_size>::swap_value(int index_i, int index_j)
{
    T tmp;
    assert(index_i>=0 && index_i<heap_size);
    assert(index_j>=0 && index_j<heap_size);
    assert(index_i!=index_j);
    tmp=values[index_i];
    values[index_i]=values[index_j];
    values[index_j]=tmp;
}

#endif // HEAP_TEMPLATE_H

You may have noticed that the heap is careful to use only the < comparison operator to do all of its comparisons between float values. Your C++ template implementation should be the same; it
should only use < for comparisons. This is done for a good reason; if you are careful in your template implementation then you can use it with any type that provides an implementation of the comparison operators.
注意到我们使用比较运算符<来完成比较操作的。所以,使用这个实例化模板类的数据类型只要支持比较运算符<就行!
例如,c++中的string类型已经实现了<运算符,所以,我们的heap类也可以存储string类型的数据。
Heap<string,10> hs;
hs.add_value("jianyong");
下面写一个完整的测试程序测试一下我们的模板类:
#include <iostream>
#include "heap_template.h"

using namespace std;

int main()
{
    Heap<int,32> h;
    srand(11);
    int i;
    for(i=0;i<32;i++)
    {
        h.add_value(rand()%1000);
    }

    for(i=0;i<32;i++)
    {
        cout<<h.get_first_value()<<endl;
    }

    try
    {
        cout<<h.get_first_value()<<endl;
    }
    catch(underflow_error &e)
    {
        cout<<e.what()<<endl;
    }

    string s1="red";
    string s2="green";
    Heap<string,10> hs;
    hs.add_value(s1);
    hs.add_value(s2);
    cout<<hs.get_first_value()<<endl;
    cout<<hs.get_first_value()<<endl;

    cout << "Hello World!" << endl;
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: