赫夫曼树的建立
文章目錄
- 赫夫曼樹的建立
- 思路
- 如圖所示
- 大致思路:
- 將所有具有權(quán)重的葉子節(jié)點(diǎn)一字排開,在其中找到的權(quán)重最小的兩個葉子節(jié)點(diǎn)借助一個新的節(jié)點(diǎn)(根)鏈接成一棵樹(一般兩個節(jié)點(diǎn)中權(quán)重小的為左孩子,更大的為右孩子),這個根的權(quán)重就等于那兩個葉子節(jié)點(diǎn)的權(quán)重之和,然后再將這個根放在那一堆還未選出的葉子節(jié)點(diǎn)中進(jìn)行比較,再找到其中兩個最小的節(jié)點(diǎn)鏈接成一棵樹,反復(fù)重復(fù)上述操作,直到構(gòu)建成一棵完整的赫夫曼樹(本質(zhì)上就上讓權(quán)重越大的葉子節(jié)點(diǎn)越靠近根節(jié)點(diǎn))
- 構(gòu)造步驟
- 借助一個結(jié)構(gòu)體數(shù)組存儲這個赫夫曼樹,結(jié)構(gòu)體中包含權(quán)重,雙親的數(shù)組下標(biāo),左孩子的數(shù)組下標(biāo),右孩子的數(shù)組下標(biāo),一個標(biāo)志節(jié)點(diǎn)是否已被建造的flag(直接用雙親判斷也可以);
- 1.先初始化這個赫夫曼樹:
- 將結(jié)構(gòu)體中所有的數(shù)據(jù)賦予0值。
- 2.創(chuàng)造赫夫曼樹(借助一個函數(shù)尋找最小權(quán)重的兩個節(jié)點(diǎn)):
- 從第n+1個數(shù)組位置開始創(chuàng)建用來鏈接兩個葉子節(jié)點(diǎn)的“根節(jié)點(diǎn)”,在創(chuàng)建每一個“根節(jié)點(diǎn)”時,要,將兩個葉子節(jié)點(diǎn)的雙親的數(shù)組下標(biāo)存入(也就是當(dāng)前這個根節(jié)點(diǎn)的下標(biāo)),要存儲“根節(jié)點(diǎn)”的權(quán)重,左右孩子的數(shù)組下標(biāo);在尋找最小權(quán)重的兩個葉子節(jié)點(diǎn)的函數(shù)中,每找到一個節(jié)點(diǎn)時,記得將這個節(jié)點(diǎn)的flag值改為1,便于后續(xù)查找剩余節(jié)點(diǎn)中的最小節(jié)點(diǎn)時,可以跳過這個節(jié)點(diǎn)。
- 3.遍歷輸出赫夫曼樹
- 很簡單,直接將數(shù)組的每一位輸出即可。
赫夫曼樹的建立
#define _CRT_SECURE_NO_WARNINGS 1 #pragma warning(disable:6031) #include<stdio.h> #include<stdlib.h> #define N 15 #define M 2*N-1 typedef struct node {char data;//存的數(shù)據(jù)int weight;//權(quán)重int parent;//雙親的數(shù)組下標(biāo)int lchild;//左孩子的數(shù)組下標(biāo)int rchild;//右孩子的數(shù)組下標(biāo)int flag;//標(biāo)志這個節(jié)點(diǎn)是否已經(jīng)被查找到,并構(gòu)造成樹過 } Hffmantree;//int select(Hffmantree* H, int n);//查找剩余未被構(gòu)造成數(shù)的節(jié)點(diǎn)中權(quán)重最小的節(jié)點(diǎn) void init_H(Hffmantree* H, int n);//初始化赫夫曼樹 void create_H(Hffmantree* H, int n);//創(chuàng)建赫夫曼樹 void traverse_H(Hffmantree* H, int n);//遍歷輸出赫夫曼樹int main() {int n;printf("請輸入該赫夫曼樹的葉子節(jié)點(diǎn)個數(shù):");scanf("%d", &n);//便于區(qū)分已有的葉子節(jié)點(diǎn)下標(biāo)和新創(chuàng)建的“根節(jié)點(diǎn)”的數(shù)組下標(biāo)Hffmantree H[M+1];int i;for (i = 1; i <= n; i++){H[i].data = 64 + i;H[i].weight = i;}//存入赫夫曼樹節(jié)點(diǎn)的數(shù)據(jù)'A','B','C','D'......for (i = n+1; i <= 2*n-1; i++){H[i].data = ' ';}init_H(H, n);traverse_H(H, n);//輸出一次初始化的赫夫曼樹create_H(H, n);traverse_H(H, n);//輸出一次構(gòu)造好的赫夫曼樹 }void init_H(Hffmantree *H, int n) {int i = 0;for (i = 1; i <= n; i++){H[i].parent = 0;H[i].lchild = 0;H[i].rchild = 0;H[i].flag = 0;}//初始化原本的葉子節(jié)點(diǎn)for (i = n + 1; i <= 2 * n - 1; i++){H[i].weight = 0;H[i].parent = 0;H[i].lchild = 0;H[i].rchild = 0;H[i].flag = 0;}//初始化將要構(gòu)造的“根節(jié)點(diǎn)” }int select(Hffmantree* H, int n) {int i = 0;int min=0;//存放權(quán)重最小節(jié)點(diǎn)的權(quán)重值int dex=0;//存放權(quán)重最小的節(jié)點(diǎn)的下標(biāo)for (i = 0; i <= n; i++){if (H[i].flag == 0){min = H[i].weight;dex = i;break;}}//為避免min和dex值不合理,用一個for循環(huán)找到第一個為被查找到過的節(jié)點(diǎn)的下標(biāo)和權(quán)重作為min和dex的初始化值for (i = 0; i <= n; i++){if (H[i].flag == 0){if (H[i].weight < min){min = H[i].weight;dex = i;}}}//找到最小權(quán)重的節(jié)點(diǎn)的權(quán)重值和下標(biāo)H[dex].flag = 1;//改寫flag為1,標(biāo)志該結(jié)點(diǎn)已被查找過return dex;//返回最小權(quán)重節(jié)點(diǎn)的下標(biāo) }void create_H(Hffmantree* H, int n) {int i = n + 1;for (i = n + 1; i <= 2 * n - 1; i++)//從結(jié)構(gòu)體數(shù)組的第n-1位開始創(chuàng)建“根節(jié)點(diǎn)”{int a;a = select(H, i - 1);//查找當(dāng)前最小權(quán)值的節(jié)點(diǎn)下標(biāo)int b;b = select(H, i - 1);//查找第二小權(quán)值的節(jié)點(diǎn)下標(biāo)(當(dāng)然它也就是查找完最小權(quán)值節(jié)點(diǎn)之后最小的權(quán)值節(jié)點(diǎn))H[i].weight = H[a].weight + H[b].weight;//存儲“根節(jié)點(diǎn)”的權(quán)重H[i].lchild = a;//存儲“根節(jié)點(diǎn)”的左孩子下標(biāo)H[i].rchild = b;//存儲“根節(jié)點(diǎn)”的右孩子下標(biāo)H[a].parent = i;//將左孩子的雙親下標(biāo)存入H[b].parent = i;//將右孩子的雙親下標(biāo)存入} }void traverse_H(Hffmantree* H, int n) {int i = 0;printf("當(dāng)前的赫夫曼樹:\n");for (i = 1; i <= 2 * n - 1; i++){printf("%d %c %d %d %d %d %d \n",i, H[i].data, H[i].weight, H[i].parent, H[i].lchild, H[i].rchild, H[i].flag);}//遍歷輸出printf("\n"); }思路
-------------------------------從一個博主那里順來的百度圖片(感謝萬分)--------------------------------------
如圖所示
大致思路:
將所有具有權(quán)重的葉子節(jié)點(diǎn)一字排開,在其中找到的權(quán)重最小的兩個葉子節(jié)點(diǎn)借助一個新的節(jié)點(diǎn)(根)鏈接成一棵樹(一般兩個節(jié)點(diǎn)中權(quán)重小的為左孩子,更大的為右孩子),這個根的權(quán)重就等于那兩個葉子節(jié)點(diǎn)的權(quán)重之和,然后再將這個根放在那一堆還未選出的葉子節(jié)點(diǎn)中進(jìn)行比較,再找到其中兩個最小的節(jié)點(diǎn)鏈接成一棵樹,反復(fù)重復(fù)上述操作,直到構(gòu)建成一棵完整的赫夫曼樹(本質(zhì)上就上讓權(quán)重越大的葉子節(jié)點(diǎn)越靠近根節(jié)點(diǎn))
構(gòu)造步驟
借助一個結(jié)構(gòu)體數(shù)組存儲這個赫夫曼樹,結(jié)構(gòu)體中包含權(quán)重,雙親的數(shù)組下標(biāo),左孩子的數(shù)組下標(biāo),右孩子的數(shù)組下標(biāo),一個標(biāo)志節(jié)點(diǎn)是否已被建造的flag(直接用雙親判斷也可以);
1.先初始化這個赫夫曼樹:
將結(jié)構(gòu)體中所有的數(shù)據(jù)賦予0值。
2.創(chuàng)造赫夫曼樹(借助一個函數(shù)尋找最小權(quán)重的兩個節(jié)點(diǎn)):
從第n+1個數(shù)組位置開始創(chuàng)建用來鏈接兩個葉子節(jié)點(diǎn)的“根節(jié)點(diǎn)”,在創(chuàng)建每一個“根節(jié)點(diǎn)”時,要,將兩個葉子節(jié)點(diǎn)的雙親的數(shù)組下標(biāo)存入(也就是當(dāng)前這個根節(jié)點(diǎn)的下標(biāo)),要存儲“根節(jié)點(diǎn)”的權(quán)重,左右孩子的數(shù)組下標(biāo);在尋找最小權(quán)重的兩個葉子節(jié)點(diǎn)的函數(shù)中,每找到一個節(jié)點(diǎn)時,記得將這個節(jié)點(diǎn)的flag值改為1,便于后續(xù)查找剩余節(jié)點(diǎn)中的最小節(jié)點(diǎn)時,可以跳過這個節(jié)點(diǎn)。
3.遍歷輸出赫夫曼樹
很簡單,直接將數(shù)組的每一位輸出即可。
總結(jié)
- 上一篇: 华为无线之充电小结
- 下一篇: PUBG绿色玩家 看过来!