数据结构与算法-哈夫曼树与哈夫曼编码

441 阅读3分钟

哈夫曼树

哈夫曼编码

哈夫曼树的实现思路

  1. 初始化哈夫曼二叉树
  2. 循环不断找到结点中,最小的2个结点值.加入到哈夫曼树中
//结点数据
typedef struct HaffNode{
    int weight;
    int flag;
    int parent;
    int leftChild;
    int rightChild;
}HaffNode;

//构建哈夫曼树
void Haffman(int weight[],int n,HaffNode haffTree[]){
    
    int j,m1,m2,x1,x2;
    
    //1.哈夫曼树初始化
    //n个叶子 结点2n-1
    for(int i = 0; i < 2*n-1;i++){
        
        if(i<n)
            haffTree[i].weight = weight[i];
        else
            haffTree[i].weight = 0;
        
        haffTree[i].parent = 0;
        haffTree[i].flag = 0;
        haffTree[i].leftChild = -1;
        haffTree[i].rightChild = -1;
    }
    
    //2.构造哈夫曼树haffTree的n-1个非叶结点
    for (int i = 0; i< n - 1; i++){
         m1 = m2 = MaxValue;  // 存储值
         x1 = x2 = 0;  //存储下标
        //2,4,5,7
        for (j = 0; j< n + i; j++)//循环找出所有权重中,最小的二个值--morgan
        {
            if (haffTree[j].weight < m1 && haffTree[j].flag == 0)
            {
                m2 = m1;
                x2 = x1;
                m1 = haffTree[j].weight;
                x1 = j;
            } else if(haffTree[j].weight<m2 && haffTree[j].flag == 0)
            {
                m2 = haffTree[j].weight;
                x2 = j;
            }
        }

        // n+i 标示顶点数组的下标,当前未构建哈夫曼树时定点存储的只有叶子结点数据,n+i开始继续存储
        //3.将找出的两棵权值最小的子树合并为一棵子树
        haffTree[x1].parent = n + i;
        haffTree[x2].parent = n + i;
        //将2个结点的flag 标记为1,表示已经加入到哈夫曼树中
        haffTree[x1].flag = 1;
        haffTree[x2].flag = 1;
        //修改n+i结点的权值
        haffTree[n + i].weight = haffTree[x1].weight + haffTree[x2].weight;
        //修改n+i的左右孩子的值
        haffTree[n + i].leftChild = x1;
        haffTree[n + i].rightChild = x2;
    }
    
}
    
    
}

哈夫曼编码的实现思路

  1. 获取根据权值构建的哈夫曼树
  2. 循环遍历[0,n]个结点;
  3. 创建临时结点cd,从根结点开始对齐进行编码,左孩子为0,右孩子为1;
  4. 将编码后的结点存储 naffcodel
  5. 设置 Haffcode]的开始位置以及权值;
/*哈夫曼编码
 由n个结点的哈夫曼树haffTree构造哈夫曼编码haffCode,构建哈夫曼编码方式
 */

void HaffmanCode(HaffNode haffTree[], int n, Code haffCode[])
{
    //1.创建一个结点cd
    Code *cd = (Code * )malloc(sizeof(Code));
    int child, parent;
    //2.求n个叶结点的哈夫曼编码
    for (int i = 0; i<n; i++)
    {
        //从0开始计数
        cd->start = 0;
        //取得编码对应权值的字符
        cd->weight = haffTree[i].weight;
        //当叶子结点i 为孩子结点.
        child = i;
        //找到child 的双亲结点;
        parent = haffTree[child].parent;
        //由叶结点向上直到根结点
        while (parent != 0)
        {
            if (haffTree[parent].leftChild == child)
                cd->bit[cd->start] = 0;//左孩子结点编码0
            else
                cd->bit[cd->start] = 1;//右孩子结点编码1
            //编码自增
            cd->start++;
            //当前双亲结点成为孩子结点
            child = parent;
            //找到双亲结点
            parent = haffTree[child].parent;
        }
        
         int temp = 0;

        for (int j = cd->start - 1; j >= 0; j--){
            temp = cd->start-j-1;
            haffCode[i].bit[temp] = cd->bit[j];
        }
      
        //把cd中的数据赋值到haffCode[i]中.
        //保存好haffCode 的起始位以及权值;
        haffCode[i].start = cd->start;
        //保存编码对应的权值
        haffCode[i].weight = cd->weight;
    }
}