数据结构与算法基础(王卓)(21):哈夫曼编码(2):结果

根据上一节的学习,写出的最终结果如下:

#include
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()
{

}

不过这玩意依然会报错:

我是真nm无语,,


最后后面在老师的网课的评论区里面,看到一个Github上面用栈实现该算法的实例,但是只有函数体,而且变量设置的有点奇怪

修修改改最终结果如下:(大概就是正确答案了)

//顺序栈
#include
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()
{

}

所以说啊兄弟们,还是要拥有自己独立思考的能力

网课的方法不一定就是对的,就是最好的

最后还不是要靠栈来实现


个人学习路程:

那就自己再默写手撕一遍呗:(只写函数体)

Project 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 (ParentP != 0)

(3):

最后输出时,需要把第i位的哈夫曼编码一位一位逐个输出,程序需要重新编写

(4):

程序里面没有给for循环的 i 赋初值


Project 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);//清空顺序栈
    }
}

ENDL

你可能感兴趣的:(数据结构(王卓),c++,算法,数据结构)