數據結構(複習)--------關於赫夫曼樹和其編碼

一、基本概念


a、路徑和路徑長度
算法

若在一棵樹中存在着一個結點序列 k1,k2,……,kj, 使得 ki是ki+1 的雙親(1<=i<j),則稱此結點序列是從 k1 到 kj 的路徑。數組

從 k1 到 kj 所通過的分支數稱爲這兩點之間的路徑長度,它等於路徑上的結點數減1.數據結構


b、結點的權和帶權路徑長度
ide

在許多應用中,經常將樹中的結點賦予一個有着某種意義的實數,咱們稱此實數爲該結點的權,(以下面一個樹中的藍色數字表示結點的權)編碼

結點的帶權路徑長度規定爲從樹根結點到該結點之間的路徑長度與該結點上權的乘積。spa


c、樹的帶權路徑長度.net

樹的帶權路徑長度定義爲樹中全部葉子結點的帶權路徑長度之和,公式爲:指針


其中,n表示葉子結點的數目,wi 和 li 分別表示葉子結點 ki 的權值和樹根結點到 ki 之間的路徑長度。code

以下圖中樹的帶權路徑長度 WPL = 9 x 2 + 12 x 2 + 15 x 2 + 6 x 3 + 3 x 4 + 5 x 4  =  122
orm



d、哈夫曼樹

哈夫曼樹又稱最優二叉樹。它是 n 個帶權葉子結點構成的全部二叉樹中,帶權路徑長度 WPL 最小的二叉樹。

以下圖爲一哈夫曼樹示意圖。


二、構造哈夫曼樹


假設有n個權值,則構造出的哈夫曼樹有n個葉子結點。 n個權值分別設爲 w一、w二、…、wn,則哈夫曼樹的構造規則爲:


(1) 將w一、w二、…,wn當作是有n 棵樹的森林(每棵樹僅有一個結點);


(2) 在森林中選出兩個根結點的權值最小的樹合併,做爲一棵新樹的左、右子樹,且新樹的根結點權值爲其左、右子樹根結點權值之和;


(3)從森林中刪除選取的兩棵樹,並將新樹加入森林;


(4)重複(2)、(3)步,直到森林中只剩一棵樹爲止,該樹即爲所求得的哈夫曼樹。


 如:對 下圖中的六個帶權葉子結點來構造一棵哈夫曼樹,步驟以下:


注意:爲了使獲得的哈夫曼樹的結構儘可能惟一,一般規定生成的哈夫曼樹中每一個結點的左子樹根結點的權小於等於右子樹根結點的權。


具體算法以下:

 

[cpp]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
 
  1. //二、根據數組 a 中 n 個權值創建一棵哈夫曼樹,返回樹根指針 structint int struct sizeofstruct for  
  2. sizeofstruct for  
  3.   
  4. int for  
  5. if continue if break for  
  6. if if elseif   
  7. sizeofstruct   
  8.   
  9.   
  10. return  
  11. }  

 

三、哈夫曼編碼

在電報通訊中,電文是以二進制的0、1序列傳送的,每一個字符對應一個二進制編碼,爲了縮短電文的總長度,採用不等長編碼方式,構造哈夫曼樹,

將每一個字符的出現頻率做爲字符結點的權值賦予葉子結點,每一個分支結點的左右分支分別用0和1編碼,從樹根結點到每一個葉子結點的路徑上

所經分支的0、1編碼序列等於該葉子結點的二進制編碼。如上文所示的哈夫曼編碼以下:

a 的編碼爲:00

b 的編碼爲:01

c 的編碼爲:100

d 的編碼爲:1010

e 的編碼爲:1011

f 的編碼爲:11

 -------------------------------------------------------------------------------------------------------------------------------------------------------------

上述來自於:http://blog.csdn.net/yaoowei2012/article/details/18180769

--------------------------------------------------------------------------------------------------------------------------------------------------

 

-------------------------------------------------------------------------------------------------------------------------------------------------------

主要是用本身的思惟去構建一顆真實的赫夫曼樹;將數組先排好序,

而後每次取前面兩個元素相加獲得分支點再將其插入到有序的數組中去;

----------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

 

// // 關於數據結構的總結與複習  Coding
//關於二叉樹的創建以及層次,其餘遍歷(遞歸,非遞歸)求深度等基本操做
//binary search tree ;  balance binary tree ; bred and black tree ; huffmantree;

#include <cstdio>
#include <cstdlib>
//#define _OJ_
#define maxsize 100
static int code[30][30];
int t = 0;

typedef struct tree
{
    int data;
    struct tree *left;
    struct tree *right;
} tree, *Bitree;

typedef struct stack1
{
    Bitree *elem;
    int base;
    int top;
} stack1, *stack;

stack
Init_stack(void)
{
    stack s;
    s = (stack) malloc (sizeof(stack1));
    s->elem = (Bitree*) malloc (sizeof(Bitree));
    s->base = s->top = 0;
    return s;
}

int
isempty(stack s)
{
    if(s->base = s->top)
        return 1;
    else
        return 0;
}


void
push(stack s, Bitree T)
{
    if(s->top > maxsize) {
        printf("棧已滿:\n");    exit(1);
    }
    else
    s->elem[s->top++] = T;
}

Bitree
pop(stack s)
{
    if(s->top == s->base) {
        printf("棧爲空:\n");    exit(1);
    }
    else
        return s->elem[--s->top];
}

Bitree
Creat_huffman(int a[], int n)
//用數組創建一顆赫夫曼樹   
{
    int i, j, t;
    Bitree *T;Bitree T1;

    T = (Bitree*) malloc (100 * sizeof(Bitree));
    for (i = 0; i < n; i++) {
         for (j = 0; j < n - i - 1; j++) {
              if(a[j] > a[j + 1]) {
            t = a[j];  a[j] = a[j + 1];  a[j + 1] = t;
           }//對數組進行排序待排完以後將其放置最後一個
    }
        T1 = (Bitree) malloc (sizeof(tree));    T1->left = T1->right = NULL;
        T1->data = a[j];    T[j] = T1;
    }
// ------------------------------------------------------------------
    i = -1;
    while (i < n - 2) {
    T1 = (Bitree) malloc (sizeof(tree));
    T1->left = T[++i];    T1->right = T[++i];
    T1->data = T1->left->data + T1->right->data;
    //已經排好序了則能夠從最小的兩個開始相加
    for (j = i + 1; j < n; j++) {
        if(T1->data < T[j]->data) {
            for (int j1 = n; j1 > j; j1--)
                T[j1] = T[j1 - 1];        break;
        }//相加的結果做爲新的數據插入數組其中
     }
    T[j] = T1;         n++;
    }

    return T1;
}

void
huffman_coding(Bitree T, int len)
{
    int i;
    static int a[20];
    if(T->left == NULL && T->right == NULL) {
    printf("%d的赫夫曼編碼爲:\n", T->data);    code[t][0] = T->data;
        for (i = 0; i < len; i++) {
            printf("%d", a[i]);
            code[t][i + 1] = a[i];
        }//第0個存入data數據第一個開始存入編碼最後一個2用作結束的標誌
         code[t++][i + 1] = 2;
            printf("\n");
    }else{

        a[len] = 0;
        huffman_coding(T->left, len + 1);
        a[len] = 1;
        huffman_coding(T->right, len + 1);
    }
}

int
deep_huffman(Bitree T)
//求huffman的深度(即爲求二叉樹的的深度同樣)
{
    int deep = 0, dept = 0, dept1 = 0;
    if(T) {
        dept = deep_huffman(T->left);
        dept = deep_huffman(T->right);
        deep = dept > dept1 ? dept + 1 : dept1 + 1;
    }
    return deep;
}

int
wpl_huffman(Bitree T, int len)
//求赫夫曼樹的帶權路徑長度weight_path_length
{
    if(T->left == NULL && T->right == NULL) {
        return T->data * len;
    }
    else
        return wpl_huffman(T->left, len + 1) + wpl_huffman(T->right, len + 1);
}

int main(int argc, char const *argv[]) {
#ifndef _OJ_ //ONLINE JUDGE
       freopen("input.txt", "r", stdin);
       //freopen("output.txt", "w", stdout);
#endif
    
    Bitree T;
    int i, j = 0, n;
    int a[100];
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
    scanf("%d", &a[i]);
    T = Creat_huffman(a, n);

    printf("huffman_deep == %d\n", deep_huffman(T));
    printf("wpl_huffman  == %d\n", wpl_huffman(T, 0));
    huffman_coding(T, 0);

    int next[50], next1[50];
    int max, l = 0;
    for (i = 0; i < t; i++)
        next[i] = code[i][0];    //將data給查詢表

    for (i = 0; i < t; i++) {
        max = 0;
        for (j = 0; j < t; j++)
            if(next[max] > next[j]) 
            max = j;                       //構建next1查詢表以便從小到大開始輸出
          {next1[l++] = max; next[max] = 999;}
    }

    int i1;l = 0;
    for (i = 0; i < t; i++) {
        i1 = next1[l++];          printf("\n第%d個數的赫夫曼編碼爲:", l);   j = 1;
        while (code[i1][j] < 2)
       printf("%d", code[i1][j++]);

}

    return 0;
}
    // int i, j;
    // int a[100];
    // for (i = 0; i < 26; i++)
    //     scanf("%d", &a[i]);
    // Bitree T;
    // T = Creat_huffman(a,26);
    //  huffman_coding(T, 0);

// int k, k1, k2;
// char str[20];    getchar();
// while (gets(str)) {
//     // printf("%s\n", str);
//     k  = 0;
//     while (str[k] != '\0') {
//         // printf("k == %c\n", str[k]);
//         if(str[k] == ' ') {printf(" ");k++;continue;}
//         else {
//             // next1[0] = 17;
//         k1 = next1[str[k] - 'A'];   // printf("k1 == %d", k1);
//             k2 = 1;
//     // printf("code == ");
//    while (code[k1][k2] < 2)
//    printf("%d", code[k1][k2++]);
//   }
 
//    k++;
//     }
//     // printf("ok");
//     printf("\n");
// }
// 10111110101111011100
// 11111111101001010010111101110
// 11111111101001010010111101110 10111110101111011100
相關文章
相關標籤/搜索