哈夫曼樹


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef int ELEMTYPE;

// 哈夫曼樹結點結構體
typedef struct HuffmanTree
{
    ELEMTYPE weight;
    ELEMTYPE id;        // id用來主要用以區分權值相同的結點,這里代表了下標
    struct HuffmanTree* lchild;
    struct HuffmanTree* rchild;
}HuffmanNode;

// 構建哈夫曼樹
HuffmanNode* createHuffmanTree(int* a, int n)
{
    int i, j;
    HuffmanNode **temp, *hufmTree;
    temp = malloc(n*sizeof(HuffmanNode));
    for (i=0; i<n; ++i)     // 將數組a中的權值賦給結點中的weight
    {
        temp[i] = (HuffmanNode*)malloc(sizeof(HuffmanNode));
        temp[i]->weight = a[i];
        temp[i]->id = i;
        temp[i]->lchild = temp[i]->rchild = NULL;
    }

    for (i=0; i<n-1; ++i)       // 構建哈夫曼樹需要n-1合並
    {
        int small1=-1, small2;      // small1、small2分別作為最小和次小權值的下標
        for (j=0; j<n; ++j)         // 先將最小的兩個下標賦給small1、small2(注意:對應權值未必最小)
        {
            if (temp[j] != NULL && small1==-1)
            {
                small1 = j;
                continue;
            } else if(temp[j] != NULL)
            {
                small2 = j;
                break;
            }
        }

        for (j=small2; j<n; ++j)    // 比較權值,挪動small1和small2使之分別成為最小和次小權值的下標
        {
            if (temp[j] != NULL)
            {
                if (temp[j]->weight < temp[small1]->weight)
                {
                    small2 = small1;
                    small1 = j;
                } else if (temp[j]->weight < temp[small2]->weight)
                {
                    small2 = j;
                }
            }
        }
        hufmTree = (HuffmanNode*)malloc(sizeof(HuffmanNode));
        hufmTree->weight = temp[small1]->weight + temp[small2]->weight;
        hufmTree->lchild = temp[small1];
        hufmTree->rchild = temp[small2];

        temp[small1] = hufmTree;
        temp[small2] = NULL;
    }
    free(temp);
    return hufmTree;
}

// 以廣義表的形式打印哈夫曼樹
void PrintHuffmanTree(HuffmanNode* hufmTree)
{
    if (hufmTree)
    {
        printf("%d", hufmTree->weight);
        if (hufmTree->lchild != NULL || hufmTree->rchild != NULL)
        {
            printf("(");
            PrintHuffmanTree(hufmTree->lchild);
            printf(",");
            PrintHuffmanTree(hufmTree->rchild);
            printf(")");
        }
    }
}

// 遞歸進行哈夫曼編碼
void HuffmanCode(HuffmanNode* hufmTree, int depth)      // depth是哈夫曼樹的深度
{
    static int code[10];
    if (hufmTree)
    {
        if (hufmTree->lchild==NULL && hufmTree->rchild==NULL)
        {
            printf("id為%d權值為%d的葉子結點的哈夫曼編碼為 ", hufmTree->id, hufmTree->weight);
            int i;
            for (i=0; i<depth; ++i)
            {
                printf("%d", code[i]);
            }
            printf("\n");
        } else
        {
            code[depth] = 0;
            HuffmanCode(hufmTree->lchild, depth+1);
            code[depth] = 1;
            HuffmanCode(hufmTree->rchild, depth+1);
        }
    }
}

// 哈夫曼解碼
void HuffmanDecode(char ch[], HuffmanNode* hufmTree, char string[])     // ch是要解碼的01串,string是結點對應的字符
{
    int i;
    int num[100];
    HuffmanNode* tempTree = NULL;
    for (i=0; i<strlen(ch); ++i)
    {
        if (ch[i] == '0')
            num[i] = 0;
        else
            num[i] = 1;
    }
    if(hufmTree)
    {
        i = 0;      // 計數已解碼01串的長度
        while(i<strlen(ch))
        {
            tempTree = hufmTree;
            while(tempTree->lchild!=NULL && tempTree->rchild!=NULL)
            {
                if (num[i] == 0)
                {
                    tempTree = tempTree->lchild;
                } else
                {
                    tempTree = tempTree->rchild;
                }
                ++i;
            }
            printf("%c", string[tempTree->id]);     // 輸出解碼后對應結點的字符
        }
    }
}

int main()
{
    int i, n;
    printf("請輸入葉子結點的個數:\n");
    while(1)
    {
        scanf("%d", &n);
        if (n>1)
            break;
        else
            printf("輸入錯誤,請重新輸入n值!");
    }

    int* arr;
    arr=(int*)malloc(n*sizeof(ELEMTYPE));
    printf("請輸入%d個葉子結點的權值:\n", n);
    for (i=0; i<n; ++i)
    {
        scanf("%d", &arr[i]);
    }

    char ch[100], string[100];
    printf("請連續輸入這%d個葉子結點各自所代表的字符:\n", n);
    fflush(stdin);      // 強行清除緩存中的數據,也就是上面輸入權值結束時的回車符
    gets(string);

    HuffmanNode* hufmTree = NULL;
    hufmTree = createHuffmanTree(arr, n);

    printf("此哈夫曼樹的廣義表形式為:\n");
    PrintHuffmanTree(hufmTree);
    printf("\n各葉子結點的哈夫曼編碼為:\n");
    HuffmanCode(hufmTree, 0);

    printf("要解碼嗎?請輸入編碼:\n");
    gets(ch);
    printf("解碼結果為:\n");
    HuffmanDecode(ch, hufmTree, string);
    printf("\n");

    free(arr);
    free(hufmTree);

    return 0;
} 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM