データ構造とアルゴリズムの基礎 (Wang Zhuo) (23): ハフマン符号化 (2): 結果

目次

前のセクションの調査によると、書かれた最終結果は次のようになります。

修正の最終結果は次のようになります: (おそらく正しい答え)

個人的な学習の旅:

プロジェクト1:

質問:

プロジェクト 2: (最終製品)


前のセクションの調査によると、書かれた最終結果は次のようになります。

#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;
    }
}


typedef char **HuffmanCode;
//typedef char** HuffmanCode;

void CreatHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n)
{
    HC = new char *[n + 1];  
    char* cd = new char[n];
    cd[n] = '\0';
    //逐字符求Huffman编码

    for (int i = 1; i <= n; i++)
    {    
        int np = n;//now point
        int pp = HT[i].parent;//parent point
        int insert = n - 1;//inser:插入

        while (HT[pp].parent != 0)
        {
            //每输入cd表1次,下次输入就向前指一个位置
            insert--;

            //往cd的最后面一位输入:左0右1
            if (HT[pp].lchild == i)
                cd[n - 1] = 0;
            else
                cd[n - 1] = 1;

            //把比较使用的结点改成parent的结点,然后进入下一轮的循环和比较
            np = pp;
            pp = HT[np].parent;
        }
        HC[i] = new char[n - insert];
        strcpy(HC[i], &cd[insert]); 
    }
    delete[]cd;
}

int main()
{

}

しかし、これはまだエラーを報告します:

本当に言葉が出ないのですが、


最後に、先生のオンライン授業のコメント欄で、Github上のスタックでアルゴリズムを実装する例を見ましたが、関数本体しかなく、変数の設定が少し変です

修正の最終結果は次のようになります: (おそらく正しい答え)

//顺序栈
#include<iostream>
using namespace std;

#define TRUE        1
#define FALSE       0
#define OK          1
#define ERROR       0
#define INFEASIBLE  -1
//#define OVERFLOW   -2   

#define MAXlength 100  
//可按需修改,PPT中写的是MAXlength

typedef int Status;
typedef int SElemType;
//注意:这一段必须写在调用SElemType类型及其指针之前

struct SqStack
{
    SElemType* base; //栈底指针  
    SElemType* top;//栈顶指针
    int stacksize; //栈可用最大容量
};

Status InitStack(SqStack& S)//构造一个空栈
{
    S.base = new SElemType[MAXlength];
    //或
    //S.base = (SElemType*)malloc(MAXlength * sizeof(SElemType));
    if (!S.base) exit(OVERFLOW);// 存储分配失败
    S.top = S.base;
    //栈顶指针等于栈底指针
    S.stacksize = MAXlength;
    return true;
}

Status StackEmpty(SqStack S)
{
    // 若栈为空,返回TRUE;否则返回FALSE 
    if (S.top == S.base)
        return TRUE;
    else
        return FALSE;
}

int StackLength(SqStack S)
{
    return S.top - S.base;
}

Status ClearStack(SqStack S)//清空顺序栈
{
    if (S.base)
        S.top = S.base;
    return OK;
}

Status DestroyStack(SqStack& S)//销毁
{
    if (S.base)
    {
        delete S.base;
        S.stacksize = 0;
        S.base = S.top = NULL;
    }
    return OK;
}

Status Push(SqStack& S, SElemType e)
{
    if (S.top - S.base == S.stacksize)
        //不是MAXlength
        return OVERFLOW;
    *S.top = e;
    S.top++;
    //也可以写成:
    //*S.top++ = e;
    return true;
}

Status Pop(SqStack& S, SElemType& e)
//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;	否则返回ERROR
{
    if (S.top == S.base) // 等价于 if(StackEmpty(S))
        return UNDERFLOW;//ERROR;
    e = *S.top;
    S.top--;
    //e = *--S.top;
    return true;
}

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

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;
    }
}

void HuffmanCode(HuffmanTree& H, const int n)
{
    //第一步:调用函数创建一个顺序存储结构的哈夫曼树,同上的函数一样
    CreateHuffmanTree(H, n);
    //第二步:遍历哈夫曼树中每一个叶子结点,也即哈夫曼数组中的前n个元素
    for (int i = 1; i <= n; ++i)
    {
        int np = n;//now point
        int pp = HT[np].parent;//parent point
        int insert = n - 1;//inser:插入
        SqStack S;
        InitStack(S);//用栈来保存

        while (np != 0)
        {
            H[pp].lchild == np ? /*0进栈*/ Push(S, 0) : /*1进栈*/ Push(S, 1);
            np = pp;
            pp = H[np].parent;
        }
        //出栈//黑框中打印编码
        while (!StackEmpty(S))
        {
            int out;
            Pop(S, out);
            cout << out;
        }
        cout << endl;
    }
}


int main()
{

}

ですから兄弟たち、あなたにはまだ独立して考える能力が必要です

オンライン授業の方法が必ずしも正しいとは限らない、それが最善である

最終的に、これを達成するためにスタックに依存する必要はありません。


個人的な学習の旅:

次に、それをサイレントに記述して、再度破棄します: (関数本体のみを記述します)

プロジェクト1:

void HuffmanCode(HuffmanTree& H, int n)//用栈实现
{
    CreateHuffmanTree(H, n);

    for (int i; i <= n; i++)
    {
        int NowP = i;
        int ParentP = H[NowP].parent;
        
        SqStack S;
        InitStack(S);

        while (ParentP != 0)
        {
            H[ParentP].lchild = NowP ? Push(S, 0) : Push(S, 1);

            NowP = ParentP;
            ParentP = H[ParentP].parent;
        }
        cout << "当叶子序号为" << i << "时,哈夫曼编码为:" << endl;
        while(!StackEmpty(S))
            Pop(S, i);
        ClearStack(S);//清空顺序栈
    }
    
}

質問:

(1):

変数 insert は書き込まれません;
insert: cd テーブルに入力した各枝 (エッジ) の対応する位置番号を示します (記録します)。

ただし、ここに書かなくても問題はなく、スタックを使ってハフマンコードを実現する場合には気にする必要はなさそうです。

(2):

次の代わりに、ノード番号 0 にジャンプしてループを終了する必要があります。

        while (親P != 0)

(3):

最終出力ではi番目のハフマンコードを1つずつ出力し、プログラムを書き換える必要がある

(4):

プログラム内の for ループの i に初期値が割り当てられていません。


プロジェクト 2: (最終製品)

void HuffmanCode(HuffmanTree& H, int n)//用栈实现
{
    CreateHuffmanTree(H, n);

    for (int i = 1; i <= n; i++)
    {
        int NowP = i;
        int ParentP = H[NowP].parent;
        
        SqStack S;
        InitStack(S);

        while (NowP != 0)
        {
            H[ParentP].lchild = NowP ? Push(S, 0) : Push(S, 1);

            NowP = ParentP;
            ParentP = H[ParentP].parent;
        }
        cout << "当叶子序号为" << i << "时,哈夫曼编码为:" << endl;
        while (!StackEmpty(S))
        {
            int a;
            Pop(S, a);
            cout << a;
        }
        cout << endl;
        ClearStack(S);//清空顺序栈
    }
}

終わり

おすすめ

転載: blog.csdn.net/Zz_zzzzzzz__/article/details/129929995