二叉树应用-Huffman树类模板的实现(数据结构基础 第6周)

简单实现来了Huffman树,在找最小堆的过程中使用到了自己做的最小堆MinHeap。
之前写的关于树的类模板中一直存在一个问题:结点的内存管理太混乱,有些甚至存在临时变量里。这里直接在类内直接定义了一个数组来存储这些结点,类析构时直接释放内存。这样应该会好点。
使用了题目二叉树应用-Huffman编码树(数据结构基础 第6周) 作简单测试。
源码
//test.cpp

#include<iostream>
#include "HuffmanTree.h"
using namespace std;

int main() {
    int n;
    cin >> n;
    int weight[100]={0};
    for(int i=0; i<n; i++) {
        cin >> weight[i];
    }
    HuffmanTree<int> ht(weight, n);
    cout << ht.weightedExternalPath() << endl;
    return 0;
}

//BinaryTreeNode.cpp

#pragma once

template <class T> class HuffmanTree;

template <class T>
class BinaryTreeNode  
{
    friend class HuffmanTree<T>;
private:
    T  element;                                         //二叉树结点数据域
    BinaryTreeNode<T>*  left;                           //二叉树结点指向左子树的指针
    BinaryTreeNode<T>*  right;                          //二叉树结点指向左子树的指针
public:
    BinaryTreeNode();
    BinaryTreeNode(const T& ele);                       //给定数据的构造函数
    BinaryTreeNode(const T& ele,BinaryTreeNode* l, BinaryTreeNode* r);//给定数据的左右指针的构造函数
    T  value() const;                                   //返回当前结点的数据
    BinaryTreeNode<T>& operator= (BinaryTreeNode<T>& Node)
    {this->element=Node.element; this->left=Node.left; this->right=Node.right;
     return *this;};                                        //重载赋值操作符
    bool operator> (BinaryTreeNode<T>& Node)
    {return this->element>Node.element;};                                       //重载>操作符
    bool operator< (BinaryTreeNode<T>& Node)
    {return this->element<Node.element;};                                       //重载<操作符
    BinaryTreeNode<T>*  leftchild() const;              //返回当前结点指向左子树的指针
    BinaryTreeNode<T>*  rightchild() const;             //返回当前结点指向右子树的指针
    void  setLeftchild(BinaryTreeNode<T>*);             //设置当前结点的左子树
    void  setRightchild(BinaryTreeNode<T>*);            //设置当前结点的右子树
    void  setValue(const T& val);                       //设置当前结点的数据域
    bool  isLeaf() const;                               //判定当前结点是否为叶结点,若是返回true
};

template<class T>
BinaryTreeNode<T>::BinaryTreeNode()
{
    left=right=NULL;
}

template<class T>
BinaryTreeNode<T>::BinaryTreeNode(const T& ele) //给定数据的构造函数
{
    element=ele;
    left=right=NULL;
}

template<class T>
BinaryTreeNode<T>::BinaryTreeNode(const T& ele,BinaryTreeNode* l, BinaryTreeNode* r)
    //给定数据的左右指针的构造函数
{
    element=ele;
    left=l;
    right=r;
}

template<class T>
T  BinaryTreeNode<T>::value() const
{
    return element; 
}

template<class T>
BinaryTreeNode<T>*  BinaryTreeNode<T>::leftchild() const
{
    return left;                                //返回当前结点指向左子树的指针
}

template<class T>
BinaryTreeNode<T>*  BinaryTreeNode<T>::rightchild() const
{
    return right;                               //返回当前结点指向右子树的指针
}   

template<class T>
void  BinaryTreeNode<T>::setLeftchild(BinaryTreeNode<T>* subroot)//设置当前结点的左子树
{
    left=subroot;
}

template<class T>
void  BinaryTreeNode<T>::setRightchild(BinaryTreeNode<T>* subroot)//设置当前结点的右子树
{
    right=subroot;
}

template<class T>
void  BinaryTreeNode<T>::setValue(const T& val) //设置当前结点的数据域
{
    element = val; 
} 

template<class T>
bool  BinaryTreeNode<T>::isLeaf() const         //判定当前结点是否为叶结点,若是返回true
{
    return (left == NULL) && (right == NULL); 
}

//HuffmanTree.cpp

#pragma once

#include"BinaryTreeNode.h"
#include "MinHeap.h"

template <class T>
class HuffmanTree  
{
private:
    BinaryTreeNode<T>* root;                        //Huffman树的树根
    BinaryTreeNode<T>* nodeArray;
    void MergeTree(BinaryTreeNode<T> &ht1,BinaryTreeNode<T> &ht2, BinaryTreeNode<T>* parent); //把ht1和ht2为根的Huffman子树合并成一棵以parent为根的二叉树
    int wep;  //带权外部路径长度
public:
    HuffmanTree(T weight[],int n);  //构造Huffman树,weight是存储权值的数组,n是数组长度  
    ~HuffmanTree();                            //析构函数
    void traverseNode(BinaryTreeNode<T>* node, int length);
    int weightedExternalPath();
};

template <class T>
void HuffmanTree<T>::MergeTree(BinaryTreeNode<T> &ht1,BinaryTreeNode<T> &ht2, BinaryTreeNode<T>* parent)
{
    parent->left=&ht1;
    parent->right=&ht2;
    parent->element=ht1.element+ht2.element;
}

template <class T>
HuffmanTree<T>::HuffmanTree(T weight[],int n):wep(0)
{
    nodeArray = new BinaryTreeNode<T>[2*n];
    MinHeap<BinaryTreeNode<T>> heap(n);         //定义最小值堆    
    BinaryTreeNode<T> NodeList;
    for(int i=0;i<n;i++)                            //初始化
    {
        NodeList.element=weight[i];
        NodeList.left=NodeList.right=NULL;
        heap.Insert(NodeList);                  //向堆中添加元素
    }
    int j=0;
    for(int i=0;i<n-1;i++)          
        //通过n-1次合并建立Huffman树
    {
        BinaryTreeNode<T> *parent;
        parent=new BinaryTreeNode<T>;
        heap.RemoveMin(nodeArray[j++]);             //选择权值最小的结点
        heap.RemoveMin(nodeArray[j++]);             //选择权值次小的结点
        MergeTree(nodeArray[j-2],nodeArray[j-1],parent);    //合并权值最小的两棵树
        heap.Insert(*parent);                       //把parent插入到堆中去
        root=parent;                                //建立根结点
    }
}

template <class T>
HuffmanTree<T>::~HuffmanTree()
{
    delete [] nodeArray;
}

template <class T>
void HuffmanTree<T>::traverseNode(BinaryTreeNode<T>* node, int length)
{
    if (node != NULL)
    {
        if (node->leftchild()==NULL && node->rightchild()==NULL)
        {
            wep += node->value()*length;
        }
        else {
            traverseNode(node->leftchild(), length+1);          //访问左子树
            traverseNode(node->rightchild(), length+1);         //访问右子树
        }
    }
}

template <class T>
int HuffmanTree<T>::weightedExternalPath()
{
    traverseNode(root, 0);
    return wep;
}

//MinHeap.cpp

#pragma once

template <class T>
class MinHeap  
{
private:
    T* heapArray;       //存放堆数据的数组
    int CurrentSize;    //当前堆中的元素数目
    int MaxSize;        //最大元素数目
public:
    MinHeap(const int n);   //构造函数,参数n为堆的最大元素数目
    virtual ~MinHeap() {delete []heapArray;};  //析构函数

    bool isLeaf(int pos) const;           //判断是否为叶节点
    int leftchild(int pos) const;        //返回左孩子位置
    int rightchild(int pos) const;       //返回右孩子位置
    int parent(int pos) const;           //返回父结点位置

    bool Remove(int pos, T& node);    //删除给定下标的元素, 返回其元素的值
    bool RemoveMin(T& node);          //从堆顶删除最小值
    bool Insert(T& newNode);   //向堆中插入新元素
    void SiftDown(int left);         //从left开始向下筛选  
    void SiftUp(int position);       //从position向上开始调整,使序列成为堆       
};

template<class T>
MinHeap<T>::MinHeap(const int n)
{
    if(n<=0)
        return;
    CurrentSize=0;
    MaxSize=n;
    heapArray=new T[MaxSize];   //创建堆空间
}

template<class T>
bool MinHeap<T>::isLeaf(int pos) const
{
    return (pos>=CurrentSize/2)&&(pos<CurrentSize);
}

template<class T>
int MinHeap<T>::leftchild(int pos) const
{
    return 2*pos+1;                     //返回左孩子位置
}

template<class T>
int MinHeap<T>::rightchild(int pos) const
{
    return 2*pos+2;                     //返回右孩子位置
}

template<class T>
int MinHeap<T>::parent(int pos) const   // 返回父节点位置
{
    return (pos-1)/2;
}

template<class T>
void MinHeap<T>::SiftDown(int left)
{
    int i=left;                         //标识父结点
    int j=2*i+1;                        //标识关键值较小的子结点       
    T   temp=heapArray[i];              //保存父结点
    //过筛
    while(j<CurrentSize)
    {
        if((j<CurrentSize-1)&&(heapArray[j]>heapArray[j+1]))
            j++;                        //j指向右子结点
        if(temp>heapArray[j])
        {
            heapArray[i]=heapArray[j];
            i=j;
            j=2*j+1;
        }
        else break;
    }
    heapArray[i]=temp;
}

template<class T>
void MinHeap<T>::SiftUp(int position) 
{//从position向上开始调整,使序列成为堆
    int temppos=position;
    T temp=heapArray[temppos];
    while((temppos>0)&&(heapArray[parent(temppos)]>temp))
    {
        heapArray[temppos]=heapArray[parent(temppos)];
        temppos=parent(temppos);
    }
    heapArray[temppos]=temp;
}

template<class T>
bool MinHeap<T>::Remove(int pos, T& node)  // 删除给定下标的元素, 返回其元素的值
{
    if((pos<0)||(pos>=CurrentSize))
        return false;
    T temp=heapArray[pos];
    heapArray[pos]=heapArray[--CurrentSize];    //用最后的元素代替被删除的元素
    if (pos>0 && (heapArray[parent(pos)] > heapArray[pos]))
        SiftUp(pos);                                //上升筛
    else SiftDown(pos);                             //向下筛       
    node=temp;
    return true;
}

template<class T>
bool MinHeap<T>::RemoveMin(T& node)
{
    if(CurrentSize==0){
        return false;
    }
    else{
        node = heapArray[0];
        heapArray[0]=heapArray[--CurrentSize];  //用最后的元素代替被删除的元素
        if (CurrentSize>1) {
            SiftDown(0);
        }
        return true;
    }
}

template<class T>
bool MinHeap<T>::Insert(T& newNode)
{//向堆中插入一个结点
    if(CurrentSize>=MaxSize)
        return false;
    heapArray[CurrentSize]=newNode;
    SiftUp(CurrentSize);
    CurrentSize++;
    return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值