数据结构-二叉树(6)哈夫曼树(Huffman树)/最优二叉树

树的路径长度是从树根到每一个结点的路径长度(经过的边数)之和。

n个结点的一般二叉树完全二叉树时取最小路径长度PL=0+1+1+2+2+2+2+…

带权路径长度=根结点到任意结点的路径长度*该结点的权。树的带权路径长度是所有叶结点的带权路径长度和。

带权路径长度WPL最小的扩充二叉树则不一定是完全二叉树,而是权值大的外结点离根结点最近的扩充二叉树。

构造Huffman树需要使用最小堆,组织森林并从中选出根结点权值最小的两棵树,组成新结点(权值等于两棵树根结点权值之和)。

假如构造的不是扩充二叉树而是扩充n叉树,则需要补充若干权值为0的结点,使得外部结点个数=内部结点个数*(n-1)+1

最优二进制编码问题可以通过构造Huffman树解决。每个出现的字符都是一个独立的结点,权值为出现的频率或次数。最终可以得到哈夫曼编码,它是一种前缀编码(没有一个编码是另一个编码的前缀)。得到的WPL可以看成最终编码得到的二进制编码的长度。

得到的哈夫曼树不唯一(因为0代表坐子树还是右子树无规定)但带权路径相同且最优。

#include "heap.h"
const int DefaultSize=20;
stract HuffmanNode{
    float data;
    HuffmanNode *leftChild,*rightChild,*parent;
    HuffmanNode():leftChild(NULL),rightChild(NULl),parent(NULL){}
    HuffmanNode(float elem,HuffmanNode *left=NULL,HuffmanNode *right=NULL,HuffmanNode *pr=NULL):data(elem),leftChild(left),rightChild(right),parent(pr){}
    bool operator<=(HuffmanNode& R){return data<=R.data;}
    bool operator>(HuffmanNode& R){return data>R.data;}
}

class HuffmanTree{
public:
    HuffmanTree(folat w[],int n);
    ~HuffmanTree(){deleteTree(root);}
protected:
    HuffmanNode *root;
    void deleteTree(HuffmanNode *t);
    void mergeTree(HuffmanNode& ht1, HuffmanNode& ht2, HuffmanNode* &parent);
}

HuffmanTree::HuffmanTree(folat w[],int n){
    //给出n个权限w[0]~w[n-1],构造Huffman树
    minHeap hp;    //使用最小堆存放森林
    HuffmanNode* parent,first,second,work;
    for(int i=0;i<n;i++){    //森林各棵树初始化
        work.data=w[i];
        work.leftChild=NULL;
        work.rightChild=NULL;
        hp.Insert(work);
    }
    for(int i=0;i<n-1;i++){   //执行n-1次mergeTree操作形成Huffman树
        hp.RemoveMin(first);
        hp.RemoveMin(second);
        mergeTree(first,second,parent);
        hp.Insert(parent);
    }
    root=parent;
}

void HuffmanTree::mergeTree(HuffmanNode *bt1,HuffmanNode *bt2,HuffmanNode& *parent){
    parent=new HuffmanNode;
    parent->leftChild=bt1;
    parent->rightChild=bt2;
    parent->data=bt1->data+bt2->data;
    bt1->parent=bt2->parent=parent;
}
原文地址:https://www.cnblogs.com/yangyuliufeng/p/9448707.html