Data Structure and Algorithm Fundamentals (Wang Zhuo) (22): Huffman Tree

Table of contents

Precondition: (Huffman tree structure construction)

Huffman tree construction (creation) process:

Basic core process (principle):

Part 1:

(1): 2n and 2 * n are completely different

(2): Does the statement of continuous assignment here affect the final result of the program?

Part 2:

First edition:

Questions found after checking the standard answers:

final version:

Select function:

Personal version (the one I wrote):

Of course, the part of filtering to determine whether the statement is executed can also be changed to:

The writing of some standard answers found: (There are some differences in the structure of traversal ideas)

So, in addition to the problem of algorithm complexity, is it feasible to put the first value directly instead of the way he assigns the initial value here? ? ?

Final product:


Precondition: (Huffman tree structure construction)

#include<iostream>
using namespace std;

struct HTNode
{
    int weight;
    int parent;
    int lchild, rchild;
};
typedef HTNode* HuffmanTree;
HuffmanTree HT;//既表示指针又表示整个数组

typedef int Status;

Huffman tree construction (creation) process:

Basic core process (principle):

1. The structural forest is all roots;

2. Choose two small trees to build new trees;

3. Delete the two small add newcomers;

4. Repeat 2 and 3 to leave a single root


Part 1:

void CreateHuffmanTree(HuffmanTree& H, int n) //已知输入有n个结点
{ 
    //1、构造森林全是根
    int m = 2 * n - 1;
    //数组共2n-1个有效元素
    H = new HTNode[m + 1];
    //第0位空置
    for (int i = 1; i <= m ; i++)
        H[i].lchild = H[i].parent = H[i].rchild = 0;
    for (int i = 1; i <= n; i++)
        cin >> H[i].weight;

I won’t repeat the mistakes I made here one by one, but just take out a few of the pits I have stepped on:

(1): 2n and 2 * n are completely different

The problem comes from: int m = 2 * n - 1;

Guess: (But it should be right)

2n should represent a single (defined) variable

 2 * n should be the result of multiplying n twice

(2): Does the statement of continuous assignment here affect the final result of the program?

It should not be affected. The operations performed by the program are just assignments one by one from right to left. This does not affect the operation results:


Part 2:

First edition:

    //   2、选用两小造新树;
    //   3、删除两小添新人;
    //   4、重复 2、3 剩单根
    int s1, s2;
    for (; n <= m; n++)
    {
        Select(H, n - 1, s1, s2);
        H[n].weight = H[s1].weight + H[s2].weight;
        H[s1].parent = H[s2].parent = n;
        //如何限制让这两个已经被取出来使用过的元素在后面的循环不再被使用:
        //在Select函数里面添加限制条件:
        //我们只筛选比较选中范围内parent属性为0的元素
        H[n].lchild = s1;
        H[n].rchild = s2;   
    }

Questions found after checking the standard answers:

(1): Our new element should start from (n+1)

(2): Is it necessary to set a new variable i to record the whole process of subsequent traversal instead of directly passing the letter n?

I think: (not necessarily correct, but also need to verify)

This question here is actually a false proposition, because even if we write according to your question here, it is written as:

    for (int n = n + 1; n <= m; n++)

The end result is actually:

We construct a new variable

More directly: this n is not that n

The n defined in this statement here is only one: the effective scope is an internal local variable of the for loop statement

(3): Similarly, does the continuous assignment here affect the final result? ?

Same as above (similarly), it does not affect


final version:

    //   2、选用两小造新树;
    //   3、删除两小添新人;
    //   4、重复 2、3 剩单根
    int s1, s2;
    for (int i = n + 1; i <= m; i++)
    {
        Select(H, i - 1, s1, s2);
        H[i].weight = H[s1].weight + H[s2].weight;
        H[s1].parent = H[s2].parent = i;
        //如何限制让这两个已经被取出来使用过的元素在后面的循环不再被使用:
        //在Select函数里面添加限制条件:
        //我们只筛选比较选中范围内parent属性为0的元素
        H[i].lchild = s1;
        H[i].rchild = s2;

At this point the program is not finished:


Select function:


Personal version (the one I wrote):

void Select(HuffmanTree HT,int n,int &r1,int &r2)
{  
    //筛选查找出当前:
    // 第一位到第n位当中:parent属性为0、weight最小的节点
    //并把他们的序号赋值给r1和r2返回

    r1 =r2= 1;
    for (int i = 1; i <= n; i++)
    {
        if (HT[i].parent == 0)
        {
            if (HT[i].weight <= HT[r1].weight)
            {
                r2 = r1;
                r1 = i;
            }
        }
    }
}

Of course, the part of filtering to determine whether the statement is executed can also be changed to:

    for (int i = 1; i <= n; i++)
    {
        if (HT[i].parent == 0 && HT[i].weight <= HT[r1].weight)
        {
            r2 = r1;
            r1 = i;
        }
    }

Of course, whether there are loopholes in this kind of writing remains to be verified.


The writing of some standard answers found: (There are some differences in the structure of traversal ideas)

void Select(HuffmanTree& HT, int n, int& s1, int& s2)
{
    /*找第一个最小值*/
    int min;//用来存放最小值
    for (int i = 1; i <= n; i++)
    {
        if (HT[i].parent == 0)
        {
            min = i;
            break;
            //注意:这里我们的 break语句,让我们直接跳出for语句
            //但是说实话,这里他这个语句的操作是什么意思(想干嘛)我属实是没看懂:
            //把前面的n个元素全部遍历一遍,把第一个parent等于0的元素下标赋值给min,然后直接退出循环?
            //那我说实话你这个操作除了给min了一个初始值,其他跟啥也都没干有什么区别嘛...
        }
    }
    for (int i = min + 1; i <= n; i++)
    {
        if (HT[i].parent == 0 && HT[i].weight < HT[min].weight)
            // 第一位到第n位当中:parent属性为0、weight最小的节点
            min = i;
    }
    s1 = min; //第一个最小值给s1

    /*找第二个最小值*/
    for (int i = 1; i <= n; i++)
    {
        if (HT[i].parent == 0 && i != s1)
        {
            min = i;
            break;
            //同样的:把第一个非s1、parent等于0的元素下标赋值给min,退出循环
        }
    }
    for (int i = min + 1; i <= n; i++)
    {
        if (HT[i].parent == 0 && HT[i].weight < HT[min].weight && i != s1)
            // 第一位到第n位当中:parent属性为0、weight最小、非s1的节点
            min = i;
    }
    s2 = min; //第二个最小值给s2
}

So, in addition to the problem of algorithm complexity, is it feasible to put the first value directly instead of the way he assigns the initial value here? ? ?


Final product:

#include<iostream>
using namespace std;

struct HTNode
{
    int weight;
    int parent;
    int lchild, rchild;
};
typedef HTNode* HuffmanTree;
HuffmanTree HT;//既表示指针又表示整个数组

typedef int Status;

void Select(HuffmanTree& HT, int n, int& s1, int& s2)
{
    /*找第一个最小值*/
    int min;//用来存放最小值
    for (int i = 1; i <= n; i++)
    {
        if (HT[i].parent == 0)
        {
            min = i;
            break;
            //注意:这里我们的 break语句,让我们直接跳出for语句
        }
    }
    for (int i = min + 1; i <= n; i++)
    {
        if (HT[i].parent == 0 && HT[i].weight < HT[min].weight)
            min = i;
    }
    s1 = min; //第一个最小值给s1

    /*找第二个最小值*/
    for (int i = 1; i <= n; i++)
    {
        if (HT[i].parent == 0 && i != s1)
        {
            min = i;
            break;
        }
    }
    for (int i = min + 1; i <= n; i++)
    {
        if (HT[i].parent == 0 && HT[i].weight < HT[min].weight && i != s1)
            min = i;
    }
    s2 = min; //第二个最小值给s2
}

void CreateHuffmanTree(HuffmanTree& H, int n) //已知输入有n个结点
{
    //1、构造森林全是根
    int m = 2 * n - 1;
    //数组共2n-1个有效元素
    H = new HTNode[m + 1];
    //第0位空置
    for (int i = 1; i <= m; i++)
        H[i].lchild = H[i].parent = H[i].rchild = 0;
    for (int i = 1; i <= n; i++)
        //        H[i].weight = w[i - 1];
        cin >> H[i].weight;
    //   2、选用两小造新树;
    //   3、删除两小添新人;
    //   4、重复 2、3 剩单根
    int s1, s2;
    for (int i = n + 1; i <= m; i++)
    {
        Select(H, i - 1, s1, s2);
        H[i].weight = H[s1].weight + H[s2].weight;
        H[s1].parent = H[s2].parent = i;
        //如何限制让这两个已经被取出来使用过的元素在后面的循环不再被使用:
        //在Select函数里面添加限制条件:
        //我们只筛选比较选中范围内parent属性为0的元素
        H[i].lchild = s1;
        H[i].rchild = s2;
    }
}

int main()
{

}

Guess you like

Origin blog.csdn.net/Zz_zzzzzzz__/article/details/129874403