哈夫曼树--最优二叉树

哈夫曼树,又称最优树,是一类带权路径长度最短的树。
路径:从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径
路径长度:路径上的分支数目称作路径长度
树的路径长度:从树根到每一个每一个结点的路径长度之和。
结点的带权路径长度:从该结点到树根之间的路径长度与结点上权的乘积。
树的带权路径长度:树中所有叶子结点的带权路径长度之和

这里写图片描述

上图中
结点对应的路径如下:
a:0
b:10
c:110
d:111

万万注意的是内存的释放,可以用析构函数,因为编译器会自动调用析构函数这样就省了很多力气

实现哈夫曼数的代码

Huffman.h

#pragma once
typedef struct HufNode
{
    char data;
    int leftchild;
    int rightchild;
    int parent;
    int weight;     // 字符的权值
    char* code;   // 字符的编码
    ~HufNode()
    {
        free(code);
    }
}Hnode, *Pnode;

class Huflist
{
    int num;//结点个数
    Pnode list;//链表
public:
    Huflist(int n);
    int getSize();
    void Select(Pnode list, int* s1, int *s2, int size);
    ~Huflist()
    {
        free(list);
    }
    void getData(int n);
    void Show();
};

Huffman.cpp

#include "Huffman.h"
#include <malloc.h>
#include <iostream>

#define MAX 1024//权的最大值
using namespace std;


Huflist::Huflist(int n)
{
    num = n;
    list = (Pnode)malloc(sizeof(Hnode)*(num + 1));//创建相应的数组
}

int Huflist::getSize()
{
    return num;
}

void Huflist::Select(Pnode list, int* s1, int *s2, int size)//list中选择parent为0,并且weight最小的两个结点,其序号由指针变量s1,s2指示
{
    int min = MAX;
    for (int i = 1; i <= size; ++i)
    {
        if (list[i].weight < min&&list[i].parent == 0)
        {
            min = list[i].weight;
            *s1 = i;
        }
    }//找出了最小的

    min = MAX;
    for (int i = 1; i <= size; ++i)
    {
        if (list[i].weight < min&&list[i].parent == 0 && i != *s1)
        {
            min = list[i].weight;
            *s2 = i;
        }
    }//找出了第二的
}

void Huflist::getData(int n)//4
{
    //0结点留下来
    for (int i = 1; i <= n; ++i)
    {
        cout << "请输入结点的数据和权值\n";
        cin >> list[i].data >> list[i].weight;
        list[i].parent = list[i].leftchild = list[i].rightchild = 0;//初始先将所有的结点挂在0下标下
    }
    //             5       7
    int s1;
    int s2;
    for (int i = n + 1; i <= num; ++i)
    {
        Select(list, &s1, &s2, num);
        cout << s1 << endl << s2 << endl;
        list[i].weight = list[s1].weight + list[s2].weight;
        list[i].parent = 0;
        list[s1].parent = i;
        list[s2].parent = i;
        list[i].leftchild = s1;
        list[i].rightchild = s2;
    }

    for (int i = 1; i <= (num + 1) / 2; ++i)
    {
        list[i].code = (char*)malloc((num + 1) / 2);
        memset(list[i].code, 0, (num + 1) / 2);
    }

    for (int i = 1; i <= (num + 1) / 2; ++i)
    {
        int p = list[i].parent;
        int start = (num + 1) / 2 - 1;//3
        int c = i;
        for (; p; p = list[p].parent)
        {
            if (list[p].leftchild == c)
            {
                list[i].code[start--] = '0';//左边0,右边1
            }
            else
            {
                list[i].code[start--] = '1';
            }
            c = p;
        }
    }

}

void Huflist::Show()
{
    for (int i = 1; i <= (num + 1) / 2; ++i)
    {
        int start = (num + 1) / 2 - 1;//3
        int j = 0;
        cout << list[i].data;
        cout << "  ";
        while (list[i].code[start] != '\0')
        {
            j++;//1
            //cout << list[i].code[start];///3
            start--;
        }

        start = (num + 1) / 2 - 1;
        for (int z = j; z > 0; z--)//z = 1
        {
            cout << list[i].code[start-z+1];
        }

        cout << endl;
    }
}

main.c

#include <iostream>
#include "Huffman.h"

using namespace std;

int main()
{
    int numOfNode;

    cout << "请输入您要输入的结点个数\n";
    cin >> numOfNode;
    int m = 2 * numOfNode - 1;
    Huflist h(m);//获得2*n-1个空间

    h.getData(numOfNode);
    h.Show();



    return 0;
}

静态链表实现
我在此处实现的是固定的传4但是思路什么的都是对的,小小的改一下就好了
主函数

#include <iostream>
using namespace std;

#define MAX 10
#define MAXWEIGHT 10000
#include "Huff.h"



int main()
{
    // 7 a 5 b 2 c 4 d
    List list;
    initList(&list);
    insertNode(&list, 7, 'a');
    insertNode(&list, 5, 'b');
    insertNode(&list, 2, 'c');
    insertNode(&list, 4, 'd');


    Show(list);
    cout << endl;
    Make(&list);
    Show(list);
    Code(&list, 4);//固定的
    for (int i = 0; i < 4; ++i)
    {

        cout << list.list[i].code << endl;
    }
    return 0;
}

头文件

#pragma once


typedef struct Node
{
    int flag;//检测是否被用过了
    int left;//标记左孩子是谁
    char data;//结点的值
    int right;//标记右孩子是谁
    int parent;//标记父亲是谁
    int weight;//标记权值是多少
    char code[4] = { 0 };
}Node;

typedef struct List
{
    Node list[MAX];
    int size;//几个结点
}List;

void Show(List s)
{
    for (int i = 0; i < s.size; ++i)
    {
        cout << "data = " << s.list[i].data << " "
            << "weight = " << s.list[i].weight << endl;
    }
}


void initList(List* s)
{
    s->size = 0;
}

void insertNode(List* s, int weight, char data)
{
    if (s->size < MAX)
    {
        s->list[s->size].weight = weight;
        s->list[s->size].left = -1;
        s->list[s->size].right = -1;
        s->list[s->size].parent = -1;
        s->list[s->size].data = data;
        s->list[s->size].flag = 0;//表示没有被用过
        s->size++;
    }
}

void Make(List* list)
{
    int l1;
    int l2;//最小和次小的两个下标
    int w1 = MAXWEIGHT;
    int w2 = MAXWEIGHT;//最小和次小的权值
    int n = list->size;
    for (int i = 0; i < n - 1; ++i)//3个,假设有四个结点
    {
        for (int j = 0; j < list->size; ++j)//遍历一遍,找出最小的
        {
            if (list->list[j].weight < w1&&list->list[j].flag == 0)//表示比w1小而且还没有用过
            {
                w1 = list->list[j].weight;
                l1 = j;
            }
        }
        list->list[l1].flag = 1;//表示被用了,开始找次小

        for (int k = 0; k < list->size; ++k)
        {
            if (list->list[k].weight < w2&&list->list[k].flag == 0)
            {
                w2 = list->list[k].weight;
                l2 = k;
            }
        }
        list->list[l2].flag = 1;

        //找到了最小也找到了次小
        if (list->size < MAX)
        {
            list->list[l1].parent = list->size;
            list->list[l2].parent = list->size;
            insertNode(list, w1 + w2, NULL);
            list->list[list->size - 1].left = l1;
            list->list[list->size - 1].right = l2;//左右子孩子
            w1 = MAXWEIGHT;
            w2 = MAXWEIGHT;
        }
        else
        {
            break;
        }

    }

}

void Code(List* list, int num)//num是结点的个数(4)
//四个结点最多三层
{
    //光找叶子结点,也就是前四个
    for (int i = 0; i < num; ++i)
    {
        int n = 0;
        int tmp = i;
        while (list->list[tmp].parent != -1)
        {
            n++;
            tmp = list->list[tmp].parent;
        }//找出几层,tmp现在是头结点
        tmp = i;
        while (tmp!=-1)
        {
            if (list->list[list->list[tmp].parent].left == tmp)
            {
                //num = 4 n = 2
                list->list[i].code[n - 1] = '1';
            }
            else
            {
                list->list[i].code[n - 1] = '0';
            }
            n--;
            tmp = list->list[tmp].parent;
        }
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值