配合优先队列来实现哈夫曼树

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_44065088/article/details/102585887
#pragma once
#ifndef _HAFFU_H_
#define _HAFFU_H_

#define HAFFU typedef

HAFFU    char  TYPE_CHAR;   // 哈夫曼树结点的值域之一为 char 类型 表示出现的字符
HAFFU    int   TYPE_WIGHT;   // 哈夫曼树结点的值域之一为 int  类型 表示出现的字符的权重
HAFFU   int   NODE_NUMBER;  // 哈夫曼树的结点总数

#include <stack>
template <class T>
using Stack = std::stack<T>;

HAFFU struct haffu_c{

    /*数据部分*/
    TYPE_CHAR   elem;     // 出现的成员 
    TYPE_WIGHT    wight;   // 权重
    struct haffu_c* lchild, * rchild;  // 左孩子 和 右孩子

    /*连接部分*/
    struct haffu_c* next;    // 下一个结点的地址 这里类似于共享单链表 承载着数的结点

}haffuNode, *haffuNodeP;

// 先序遍历
void
preOrder(haffuNodeP haffu_tree);

// 中序 
void
cenOrder(haffuNodeP haffu_tree);

// 得到哈夫曼树的 所有结点数量
NODE_NUMBER
getHaffuNodeNumber(haffuNodeP haffu_tree);

// 得到哈夫曼树的所有叶子结点  返回的是所有的叶子结点的数组
TYPE_CHAR*
getHaffuLeaf(haffuNodeP haffu_tree, int maxlen);

// 求哈夫曼编码  返回的是该叶子结点的哈夫曼编码的数组 0 1(二进制) 形式
void
getHaffuCoding(haffuNodeP haffu_tree, TYPE_CHAR leaf, TYPE_CHAR*, int& index);

// 树的销毁
void
destroyTree(haffuNodeP &haffu_tree);

#endif // !_HAFFU_H_
#include <iostream>
#include "haffu_tree.h"
#include <string.h>

void
preOrder(haffuNodeP haffu_tree) 
{
    if (!haffu_tree) return;

    printf_s("--%c[%d]--", haffu_tree->elem, haffu_tree->wight);
    preOrder(haffu_tree->lchild);
    preOrder(haffu_tree->rchild);
    return;
}

void
cenOrder(haffuNodeP haffu_tree)
{
    if (!haffu_tree) return;

    preOrder(haffu_tree->lchild);
    printf_s("--%c[%d]--", haffu_tree->elem, haffu_tree->wight);
    preOrder(haffu_tree->rchild);
    return;
}


void
destroyTree(haffuNodeP &haffu_tree) 
{
    if (!haffu_tree)return;

    haffuNodeP tmp[100];

    int in = 0;
    int out = 0;
    tmp[in++] = haffu_tree;

    while (in > out) {

        if (tmp[out]) {
            tmp[in++] = tmp[out]->lchild;
            tmp[in++] = tmp[out]->rchild;
        }
        out++;
    }
    for (int i = out - 1; i > -1; i--) {
        if (tmp[i]) delete tmp[i];
    }
    return;
}

NODE_NUMBER
getHaffuNodeNumber(haffuNodeP haffu_tree)
{
    if (!haffu_tree)return 0;
    return getHaffuNodeNumber(haffu_tree->lchild)
        + getHaffuNodeNumber(haffu_tree->rchild) + 1;
}

TYPE_CHAR*
getHaffuLeaf(haffuNodeP haffu_tree, int maxlen)
{    
    if (!haffu_tree) return nullptr;  // 这是个空树
    
    // 最大一百个 叶子结点  其实 可以 根据结点总数算出来
    TYPE_CHAR* leaf = (TYPE_CHAR*)calloc(maxlen, sizeof(TYPE_CHAR));
    if (!leaf) return nullptr;
    haffuNodeP tmp = haffu_tree;    // 用于遍历的结点

    int count = 0;  // 记录叶子结点的下标

    Stack<haffuNodeP> stack;        
    stack.push(haffu_tree);

    while (!stack.empty()) {

        tmp = stack.top();    // 得到栈定元素
        if (!tmp->lchild && !tmp->rchild) {
            leaf[count++] = tmp->elem;
        }
        stack.pop();
        if (tmp->rchild)stack.push(tmp->rchild);
        if (tmp->lchild)stack.push(tmp->lchild);
    }

    return leaf;
}
#include <iostream>
#include <time.h>
#include <Windows.h>
#include "priority_queue.h"

#include <cstdlib>   //*
#include <crtdbg.h>  //*

#ifdef  _DEBUG         //*
#ifndef DBG_NEW           //*
#define DBG_NEW new (_NORMAL_BLOCK, __FILE__, __LINE__)//*
#define new DBG_NEW        //*
#endif               //*
#endif

using namespace std;

int main(void) 
{
    clock_t start, end;
    start = clock();
    priority_queueP PQ = nullptr;

    // 初始化
    if (initPriorityQueue(PQ)) {
        if (DeBug)printf_s("队列初始化成功!\n");
    }
    else {
        if (DeBug)printf_s("队列初始化失败!\n");
        exit(-1);
    }

    srand((unsigned)time(nullptr));
    // 插入
    if (DeBug)cout << "******************入队********************" << endl;
    ELEM_TYPE* node;
    for (int i = 0; i < 10; i++) {
        node = new ELEM_TYPE;
        node->elem = i + 'a';
        node->wight = 5 - i;
        node->next = nullptr;
        node->lchild = nullptr;
        node->rchild = nullptr;
        if (insertQueue(PQ, node)) {
            if (DeBug)printf_s("插入成功! \n");
        }
        else {
            if (DeBug)printf_s("插入失败!\n");
            if (node) delete node;
        }
    }
    if (DeBug) printQueue(PQ);
    cout << endl;

    // 优先队列的出队
    if (DeBug)cout << "******************出队********************" << endl;
    ELEM_TYPE* out_node = nullptr;
    for (int i = 0; i < 3; i++) {
        
        if (out_node = popQueue(PQ)){
            if (DeBug)printf_s("出队元素%c[%d] \n", out_node->elem, out_node->wight);
            if (out_node)delete out_node;
        }
        else {
            if (DeBug)printf_s("出队失败!\n");
        }
    }
    // 遍历
    if (DeBug) printQueue(PQ);
    cout << endl;
    // 构建哈夫曼树
    haffuNodeP haffu_tree = nullptr;
    buildHaffu(PQ, haffu_tree);

    // 先序遍历
    if (DeBug) cout << "哈夫曼树的先序遍历:" << endl;
    preOrder(haffu_tree);
    cout << endl;
    // 中序遍历
    if (DeBug) cout << "哈夫曼树的中序遍历:" << endl;
    cenOrder(haffu_tree);
    cout << endl;

    // 得到树的结点总数
    int maxlen = getHaffuNodeNumber(haffu_tree);
    if (DeBug) cout << "哈夫曼树的结点总数:" << maxlen << endl;
    

    // 得到树的叶子数组
    if (DeBug) cout << "哈夫曼树的叶子结点总数:" << endl;
    TYPE_CHAR* leaf_str = getHaffuLeaf(haffu_tree, maxlen);

    int reallenth = strlen(leaf_str);
    for (int i = 0; i < reallenth; i++) {
        cout << leaf_str[i] << " ";
    }
    cout << endl;

    delete[] leaf_str;
    destroyTree(haffu_tree);
    destroyQueue(PQ);
    if (DeBug) cout << "哈夫曼树  和  队列 销毁成功!" << endl;
    end = clock();
    cout << start << "   ";
    cout << end << endl;
    printf("总共用了 %d 个系统时间 \n", int(end - start));
    system("pause");
    _CrtDumpMemoryLeaks();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44065088/article/details/102585887