贪心算法-(哈夫曼编码)HuffmanCode

哈夫曼编码应用在于对于文件的压缩,压缩效率是非常的高。实现哈夫曼编码,得首先知道哈夫曼树的形成过程是怎样进行的:

1、对于所要编码的数据,首先得将它们中找到其中的最小的两个位置合并成一个小树,节点的权值是两者相加形成的;

2、步骤1中得到的权值在进入原排列中,在此获取新组合中的最小的两个数据,在执行步骤1;

3、对于步骤1、2要重复执行它,执行的次数其实可以思考一下,其实有n个数,执行的次数一定是n-1次而已。

以上是哈夫曼编码的大致形成过程,其实有很多细节的东西,还得去思考。

数据格式:

#define N 200

typedef  struct huff {

    int weight;

    char value;

    structhuff*Lchild;

    structhuff*Rchild;

} HuffumanNode;

1⃣️、这里哈夫曼树的形成过程:

HuffumanNode * CreateTree(int w[],char  *str,int n)

{

   //n代表数据长度

   HuffumanNode**container,*Huffumantree=NULL;

   //申请一个空间去保存数据

    container=(HuffumanNode**)malloc(n*sizeof(HuffumanNode));

    //save data

    for(int i=0;i<n;i++){

        container[i]=(HuffumanNode*)malloc(sizeof(HuffumanNode));

        container[i]->weight=w[i];

  container[i]->value=str[i];

        container[i]->Lchild=container[i]->Rchild=NULL;

    }//这里你要保存数据当然不适用地址,而是用空间去保存,这里要去申请一个空间;

    //下面我们是不是要进入创建树的过程了,那么它执行的此时就是n-1次

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

   {

       //这里我们得先找出其中最小的权值两个数据组成树

int small1=-1,small2;

        for(int j=0;j<n;j++)

        {

            if(small1==-1&&container[j]!=NULL)

          {

                small1=j;

                continue;

           }

             if(container[j]!=NULL)

             {

  small2=j;

                break;

             }

        }

     //这里获取两个小标例如0,1

     for(int j=small2;j<n;j++)

      {  

         if(container[j]){

              if(container[j]->weight<container[small1]->weight){

                small2=small1;

  small1=j; 

             }

              if(container[j]->weight<container[samll2]->weight)

                 small2=j;

    }

      }

        //这里就获取最小两个数据的下标了。

       Huffumantree=(HuffumanNode*)malloc(sizeof(HuffumanNode));

       Huffumantree->weight=container[small1]->weight+container[small2]->weight;

      //这里你可以把小的放在左边,当然也可以是右边,都是一样的只要下面换一下就可以实现了.

       Huffumantree->Lchild=container[small1];

       Huffumantree->Rchild=container[small2];

       container[small1]=Huffumantree;

//这点非常重要的,这就是在此进入容器中参与找出最小的两个数据,指针下移

       container[small2]=NULL:

    }

}

我们可以看一下树建成功了,打印一下。

非递归前序打印一下:

//stack---->

#define InISize 20
#define AppSize 50
typedef struct Stack{
    int Capacity;
    HuffumanNode*base;
    HuffumanNode*top;
}Stack;
typedef struct queue{
    HuffumanNode *rear;
    HuffumanNode *front;
    int size;
}Queue;
void IniStack(Stack *s)
{
    s->base=(HuffumanNode*)malloc(InISize*sizeof(HuffumanNode));
    if(!s->base)
        return ;
    s->top=s->base;
    s->Capacity=InISize;
}
int EmptyStack(Stack *s)
{
    if(s->base==s->top)
    {
        return 1;
    }
    else
        return 2;
}
void ClearStack(Stack *s)
{
    s->top=s->base;
}
void Push(Stack *s,HuffumanNode d)
{
    
    if(s->top-s->base>=s->Capacity)
    {
        s->base=(HuffumanNode *)realloc(s->base,AppSize*sizeof(HuffumanNode));
        if(!s->base)
            return ;
        s->top=s->base+s->Capacity;
        s->Capacity=AppSize+InISize;
    }
    *(s->top)=d;
    s->top++;
}
void pop(Stack *s,HuffumanNode *D)
{
    if(s->top==s->base)
        return ;
    s->top--;
    *D=*(s->top);
}
void destroyStack(Stack *s)
{
    free(s->base);
    s->top=s->base;
    s->Capacity=0;
}
int StackSize(Stack *s)
{
    return (int)(s->top-s->base);
}
打印一下:

void NoRecuirPrevios(HuffumanNode *tree)

{

    HuffumanNode*p=tree;

    Stack S;

    IniStack(&S);

    printf("(");

    while(EmptyStack(&S)!=1||p)

    {

        if(p)

        {

            printf("%d",p->weight);

            printf(",");

            Push(&S, *p);

            p=p->Lchild;

                    }

        else

        {

            

            p=(HuffumanNode*)malloc(sizeof(HuffumanNode));

            pop(&S, p);

            p=p->Rchild;

            

        }

    }

    printf(")\n");

}

//接下来表示打印哈夫曼编码了:

左子树打印0,右子树打印1;

我其实考虑用深度递归打印,那样非常简单的:

void HUffmanCoding(HuffumanNode *huffmantree,int deepth)

{

    staticint code[N];

    if(huffmantree)

    {

        //这里是从叶子的底层开始递归的,谈判断的条件便是底层便是左右孩子都没有时候就打印,这就是递归的方法;

        if(huffmantree->Lchild==NULL && huffmantree->Rchild==NULL)

        {

            cout<<"该编码对应的值是:"<<huffmantree->value<<",权值是:"<<huffmantree->weight<<"对应的编码是:";

            int i;

            for( i=0;i<deepth;++i)

            {

                cout<<code[i];

            }

            cout<<endl;

        }

        

        else

        {

            code[deepth]=0;

            HUffmanCoding(huffmantree->Lchild, deepth+1);

            code[deepth]=1;

            HUffmanCoding(huffmantree->Rchild, deepth+1);

        }

    }

}用例测试一下:


这里还有一个更佳简单的就是用数组来实现的:

数据封装:

typedef struct HuffRec

{

    double w;

    int Pr, Lch, Rch;

}HuffRec, *HuffRecPtr;

树的核心算法:

int GetMinPos(int m)

{

    int k, s;

    double Min;

    k= 0;

    Min= 9999.99;

    for(s=0; s<=m; s++)

    {

        if (HT[s].Pr==0 && HT[s].w < Min)

        {

            k=s;

            Min= HT[s].w;

        }

    }

  return k;}


for(m= N; m< 2*N- 1; m++)

    {

        i= GetMinPos(m-1);

        HT[i].Pr=m;

        j= GetMinPos(m-1);

        HT[m].Lch= i;

        HT[m].Rch= j;

        HT[m].w= HT[i].w + HT[j].w;

        HT[j].Pr= m;

    }

int GenerateCode()

{

    int i, j, m, pr;

    for(i= 0; i<N; i++)

        //

        for(j=0; j<N; j++)

        {

            Code[i][j]= 0;

        }

    //

    for (i= 0; i<N; i++)

        Start[i]= 0;

    for(i=0; i<N; i++)

    {

        m= N;

        j= i;

        //

        while(j< 2*N-2)

        {

            pr= HT[j].Pr;

            m--;

            if (j== HT[pr].Lch)

                Code[i][m]= 0;

            else

                Code[i][m]= 1;

            

            j= pr;

        }

        //

        Start[i]= m;

    }

    

    return 0;

}

 for(i= 0; i<N; i++)

    {

        printf("权值%5.1lf的哈夫曼编码是:", HT[i].w);

        //

        for(j= Start[i]; j<N; j++)

            printf("%d", Code[i][j]);

        //

        printf("\n");

    }

这是其他的方法,不过我认为前面的方法还要好一点,链表要比数组节约空间。(数组是我们老师给大家参考举例而写的)
我自己写了链表的方法实现,希望各位前辈多多指教!自己还差得远呢。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
哈夫曼编码是一种可变长度编码,用于无损数据压缩。贪心算法可以用来求解哈夫曼编码。具体步骤如下: 1. 统计每个字符出现的频率,并将它们存储在一个数组中。 2. 创建一个最小堆,并将所有的字符节点插入其中。每个节点包含一个字符和它的频率。 3. 从最小堆中取出两个频率最小的节点,合并它们,并将新节点插入回最小堆中。新节点的频率为两个旧节点的频率之和。 4. 重复步骤3,直到最小堆中只剩下一个节点为止。这个节点就是哈夫曼树的根节点。 5. 遍历哈夫曼树,给左子树编码为0,给右子树编码为1。从根节点开始,每当向左走一步就在编码末尾添加一个0,每当向右走一步就在编码末尾添加一个1。最终得到每个字符的哈夫曼编码。 以下是C++代码实现: ```c++ #include <iostream> #include <queue> #include <vector> using namespace std; struct Node { char ch; int freq; Node* left; Node* right; Node(char c, int f) : ch(c), freq(f), left(nullptr), right(nullptr) {} }; struct Compare { bool operator()(Node* a, Node* b) { return a->freq > b->freq; } }; void encode(Node* root, string code, vector<string>& codes) { if (!root) return; if (root->ch != '#') codes[root->ch] = code; encode(root->left, code + "0", codes); encode(root->right, code + "1", codes); } vector<string> huffman(vector<int>& freqs) { priority_queue<Node*, vector<Node*>, Compare> pq; for (int i = 0; i < freqs.size(); i++) { if (freqs[i] > 0) { pq.push(new Node(i, freqs[i])); } } while (pq.size() > 1) { Node* left = pq.top(); pq.pop(); Node* right = pq.top(); pq.pop(); Node* parent = new Node('#', left->freq + right->freq); parent->left = left; parent->right = right; pq.push(parent); } vector<string> codes(256); encode(pq.top(), "", codes); return codes; } int main() { string s = "hello world"; vector<int> freqs(256, 0); for (char c : s) freqs[c]++; vector<string> codes = huffman(freqs); for (int i = 0; i < 256; i++) { if (freqs[i] > 0) { cout << (char)i << ": " << codes[i] << endl; } } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值