哈夫曼树 - 完整代码

// 博客
// https://blog.csdn.net/shuangde800/article/details/7341289
// https://www.cnblogs.com/kubixuesheng/p/4397798.html
// 一个结点的权值实际上就是这个结点子树在整个树中所占的比例.
// 根据哈弗曼树的定义,一棵二叉树要使其WPL值最小
// 必须使权值越大的叶子结点越靠近根结点,而权值越小的叶子结点
// 规定哈夫曼树中所有左分支表示字符0,所有右分支表示字符1

// 1、满二叉树不一定是哈夫曼树
// 2、哈夫曼树中权越大的叶子离根越近  (很好理解,WPL最小的二叉树)
// 3、具有相同带权结点的哈夫曼树不惟一
// 4、哈夫曼树的结点的度数为 0 或 2, 没有度为 1 的结点。
// 5、包含 n 个叶子结点的哈夫曼树中共有 2n – 1 个结点。
// 6、包含 n 棵树的森林要经过 n–1 次合并才能形成哈夫曼树,共产生 n–1 个新结点

#include 
using namespace std;

typedef struct TreeNode *HuffmanTree;
// 哈夫曼树结构
struct TreeNode
{
    int Weight;
    int Code; //编码
    HuffmanTree Left, Right, Parent;
};
typedef struct HTNode *MinHeap;
typedef int ElementType;
// 堆结构
struct HTNode
{
    HuffmanTree *Data;
    int Size;     //当前的个数
    int Capacity; //容量
};
void Down(MinHeap &H, int i)
{
    // 以前的堆是用基类型作为比较的对象
    // 这个是以哈夫曼树的权重为比较对象
    // 架构不变
    int child;

    for (int parent = i; parent * 2 <= H->Size; parent = child)
    {
        child = parent * 2;
        // 在子节点中找一个小的
        if ((child != H->Size) && (H->Data[child]->Weight > H->Data[child + 1]->Weight))
            child++;
        // 最小堆 父亲要比孩子小
        // 否则 交换
        if (H->Data[parent]->Weight > H->Data[child]->Weight)
        {
            swap(H->Data[parent], H->Data[child]);
        }
        else
        {
            break;
        }
    }
}
// 建最小堆
void BuildMinHeap(MinHeap &H)
{
    H = (MinHeap)malloc(sizeof(struct HTNode));
    H->Size = 0;
    H->Capacity = 1000;
    // 堆的每一个元素都是哈夫曼树节点
    H->Data = (HuffmanTree *)malloc(sizeof(struct TreeNode) * H->Capacity);
    // 输入数据
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        if (H->Size == H->Capacity)
        {
            cout << "is full";
            break;
        }

        HuffmanTree node = (HuffmanTree)malloc(sizeof(struct TreeNode));
        node->Left = node->Right = node->Parent = NULL;
        node->Code = -1;
        // 光输入权重
        cin >> node->Weight;
        // 把哈夫曼树放到堆里
        H->Data[++H->Size] = node;
    }
    // 建堆
    for (int i = H->Size / 2; i >= 1; i--)
    {
        Down(H, i);
    }
}

//删除也是换汤不换药
HuffmanTree DeleteMin(MinHeap H)
{
    if (H->Size == 0)
    {
        cout << "空";
        return NULL;
    }
    // 得记住最小的堆
    HuffmanTree top = H->Data[1];
    // 把最后一个提上来
    H->Data[1] = H->Data[H->Size--];
    int child;
    for (int parent = 1; parent * 2 <= H->Size; parent = child)
    {
        child = 2 * parent;
        if (child != H->Size && H->Data[child]->Weight > H->Data[child + 1]->Weight)
        {
            child++;
        }
        if (H->Data[parent]->Weight > H->Data[child]->Weight)
        {
            swap(H->Data[parent], H->Data[child]);
        }
        else
            break;
    }
    return top;
}
void Insert(MinHeap &H, HuffmanTree T)
{
    if (H->Size == H->Capacity)
    {
        cout << "满";
        return;
    }
    H->Data[++H->Size] = T;
    int i = H->Size;
    while (i != 1)
    {
        int p = i / 2;
        if (H->Data[p] > H->Data[i])
            swap(H->Data[p], H->Data[i]);
        else
            break;
        i = p;
    }
}
// 建哈夫曼树
HuffmanTree Huffman(MinHeap H)
{
    // 最小堆的元素类型是HuffmanTree
    int i, N;
    HuffmanTree T;
    // 先搞一个最小堆
    BuildMinHeap(H);
    N = H->Size;
    // n-1次循环
    for (int i = 1; i < N; i++)
    {
        // 1.建一个新节点
        // 2.在现存的堆里找两个最小的放到这个节点下面
        T = (HuffmanTree)malloc(sizeof(struct TreeNode));
        // 左找一个最小的
        T->Left = DeleteMin(H);
        // 右找一个
        T->Right = DeleteMin(H);
        // 上一级的节点的权重 是 下一级节点权重的和
        T->Weight = T->Left->Weight + T->Right->Weight;
        // 记下父亲 为了好操作
        T->Left->Parent = T->Right->Parent = T;
        T->Left->Code = 0;
        T->Right->Code = 1;
        T->Code = -1;
        T->Parent = NULL;
        // 3.把新的哈夫曼树插到堆里
        Insert(H, T);
    }
    //返回头节点
    return DeleteMin(H);
}

// 输出权重
// 然后输出这个权重的编码 (左0右1)
void printHuffmanCode(HuffmanTree HF)
{
    // 因为权重是在叶子节点上
    // 所以从下往上打印
    if (HF->Parent == NULL)
    {
        return;
    }
    else
    {
        printHuffmanCode(HF->Parent);
        cout << HF->Code;
    }
}
void PreOderPrint(HuffmanTree HF)
{
    if (!HF)
        return;
    // 在叶子节点的时候
    if (!HF->Left && !HF->Right)
    {
        // 先把权重输出
        cout << HF->Weight << ": ";
        // 在去输出这个权重的编码
        printHuffmanCode(HF);
        cout << endl;
    }
    else
    {
        PreOderPrint(HF->Left);
        PreOderPrint(HF->Right);
    }
}
int main()
{
    MinHeap h;
    HuffmanTree hf = Huffman(h);
    PreOderPrint(hf);
    return 0;
}

你可能感兴趣的:(#,数据结构课程)