哈夫曼树的创建

哈夫曼树每次选取两个最小值,然后将两个最小值之和再存入到权值中,如果用数组每次都排序插入在排序,效率不高,本文采用最小堆的形式,堆中的元素为带权值的哈夫曼结点。

代码如下:

/************************************************************************
*
* 文件名:5.2.1.cpp
*
* 文件描述:哈夫曼树
*
* 创建人:  fdk

* 时  间:  2018-08-12
*
* 版本号:1.0
*
* 修改记录:
*
************************************************************************/
#include <iostream>
#include <cstdlib>
#include <algorithm>
#define MAXSIZE 164
#define MinData -100
using namespace std;
typedef struct HTNode Node; //哈夫曼树类型
struct HTNode
{
    int weight;  //结点权值
    Node *left;  //指向左子树
    Node *right; //指向右子树
};

typedef struct HNode Heap;         //堆的类型定义
struct HNode
{
    int sizes;    //堆中当前的元素个数
    Node datas[MAXSIZE];
};


Node * CreateNode(int v)
{
    Node * node = (Node*)malloc(sizeof(struct HTNode));
    node->weight = v;
    node->left = NULL;
    node->right = NULL;
    return node;
}

/*插入操作*/
void Insert(Heap *MinHeap, Node *node)
{
    /*将元素x插入最小堆,其中H->datas[0]已经定义为哨兵*/
    int i;
    i = ++MinHeap->sizes; //i指向插入后,堆中的最后一个元素的位置
    for (; MinHeap->datas[i / 2].weight > node->weight; i /= 2)
    {
        MinHeap->datas[i] = MinHeap->datas[i/2];   //上滤
    }
    MinHeap->datas[i] = *node;  //将新结点插入
}

/*创建最小堆*/
Heap * BuildHeap(int arr[], int n)
{
    Heap * MinHeap = (Heap*)malloc(sizeof(struct HNode));
    MinHeap->sizes = 0;
    MinHeap->datas[0] = *CreateNode(MinData);

    for (int i = 0; i < n; i++)
    {
        Node * node = CreateNode(arr[i]);
        Insert(MinHeap, node);
    }
    return MinHeap;
}




/*从最小堆中取出一个结点,并删除一个结点*/
Node * DeleteMin(Heap * minHeap)
{
    /*从最小堆中取出键值为最小的元素,并删除一个结点*/
    int sizes = minHeap->sizes;


    int resultsizes = minHeap->sizes--;
    Node * datas = minHeap->datas;
    Node lastnode = minHeap->datas[sizes];

    Node *firstnode = CreateNode(datas[1].weight);
    firstnode->left = datas[1].left;
    firstnode->right = datas[1].right;

    int parent;  //父结点
    int child;   //子结点
    for (parent = 1; parent * 2 <= resultsizes; parent = child)
    {
        child = parent * 2;
        if ((child != resultsizes) && (datas[child].weight > datas[child+1].weight))
        {
            child++;   //去左右子结点中最小的
        }
        if (lastnode.weight <= datas[child].weight)
        {
            break;  //找到了合适的位置
        }
        else
        {
            /*下滤*/
            minHeap->datas[parent] = minHeap->datas[child];
        }
    }
    minHeap->datas[parent] = lastnode;

    return firstnode;
}


/*哈夫曼树*/
Node * BuildHuffman(Heap * minHeap)
{
    int sizes = minHeap->sizes;
    Node * newNode;
    /*做N-1次合并*/
    for (int i = 0; i < sizes - 1; i++)
    {
        newNode = CreateNode(0);       //建立一个新的根结点
        newNode->left = DeleteMin(minHeap);  //从最小堆中删除一个结点,作为新T的左子结点
        newNode->right = DeleteMin(minHeap); //从最小堆中删除一个结点,作为新T的右子结点
        newNode->weight = newNode->left->weight + newNode->right->weight;

        Insert(minHeap, newNode);
    }
    newNode = CreateNode(0);
    newNode = DeleteMin(minHeap);
    return newNode;
}

/*打印叶子结点*/
void PrintLeaves(Node * node)
{
    if (node)
    {
        if (!node->left && !node->right)
        {
            cout << node->weight << " ";
        }
        PrintLeaves(node->left);
        PrintLeaves(node->right);
    }
}

/*递归前序遍历*/
void PreOrderTraversal(Node *node)
{
    if (node)
    {
        cout << node->weight << " ";
        PreOrderTraversal(node->left);
        PreOrderTraversal(node->right);
    }
}

/*递归中序遍历*/
void InOrderTraversal(Node *node)
{
    if (node)
    {
        InOrderTraversal(node->left);
        cout << node->weight << " ";
        InOrderTraversal(node->right);
    }
}

int main()
{
    int arr[] = {1, 2, 3, 4, 5, 6};
    int length = sizeof(arr) / sizeof(arr[0]);

    Heap *MinHeap = BuildHeap(arr, length);

    Node *Huffman = BuildHuffman(MinHeap);

    PreOrderTraversal(Huffman);
    cout << endl;

    InOrderTraversal(Huffman);
    cout << endl;

    PrintLeaves(Huffman);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/fdkNeverStopLearning/article/details/81662253