赫夫曼树的建立
文章目錄
- 赫夫曼樹(shù)的建立
- 思路
- 如圖所示
- 大致思路:
- 將所有具有權(quán)重的葉子節(jié)點(diǎn)一字排開(kāi),在其中找到的權(quán)重最小的兩個(gè)葉子節(jié)點(diǎn)借助一個(gè)新的節(jié)點(diǎn)(根)鏈接成一棵樹(shù)(一般兩個(gè)節(jié)點(diǎn)中權(quán)重小的為左孩子,更大的為右孩子),這個(gè)根的權(quán)重就等于那兩個(gè)葉子節(jié)點(diǎn)的權(quán)重之和,然后再將這個(gè)根放在那一堆還未選出的葉子節(jié)點(diǎn)中進(jìn)行比較,再找到其中兩個(gè)最小的節(jié)點(diǎn)鏈接成一棵樹(shù),反復(fù)重復(fù)上述操作,直到構(gòu)建成一棵完整的赫夫曼樹(shù)(本質(zhì)上就上讓權(quán)重越大的葉子節(jié)點(diǎn)越靠近根節(jié)點(diǎn))
- 構(gòu)造步驟
- 借助一個(gè)結(jié)構(gòu)體數(shù)組存儲(chǔ)這個(gè)赫夫曼樹(shù),結(jié)構(gòu)體中包含權(quán)重,雙親的數(shù)組下標(biāo),左孩子的數(shù)組下標(biāo),右孩子的數(shù)組下標(biāo),一個(gè)標(biāo)志節(jié)點(diǎn)是否已被建造的flag(直接用雙親判斷也可以);
- 1.先初始化這個(gè)赫夫曼樹(shù):
- 將結(jié)構(gòu)體中所有的數(shù)據(jù)賦予0值。
- 2.創(chuàng)造赫夫曼樹(shù)(借助一個(gè)函數(shù)尋找最小權(quán)重的兩個(gè)節(jié)點(diǎn)):
- 從第n+1個(gè)數(shù)組位置開(kāi)始創(chuàng)建用來(lái)鏈接兩個(gè)葉子節(jié)點(diǎn)的“根節(jié)點(diǎn)”,在創(chuàng)建每一個(gè)“根節(jié)點(diǎn)”時(shí),要,將兩個(gè)葉子節(jié)點(diǎn)的雙親的數(shù)組下標(biāo)存入(也就是當(dāng)前這個(gè)根節(jié)點(diǎn)的下標(biāo)),要存儲(chǔ)“根節(jié)點(diǎn)”的權(quán)重,左右孩子的數(shù)組下標(biāo);在尋找最小權(quán)重的兩個(gè)葉子節(jié)點(diǎn)的函數(shù)中,每找到一個(gè)節(jié)點(diǎn)時(shí),記得將這個(gè)節(jié)點(diǎn)的flag值改為1,便于后續(xù)查找剩余節(jié)點(diǎn)中的最小節(jié)點(diǎn)時(shí),可以跳過(guò)這個(gè)節(jié)點(diǎn)。
- 3.遍歷輸出赫夫曼樹(shù)
- 很簡(jiǎn)單,直接將數(shù)組的每一位輸出即可。
赫夫曼樹(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)志這個(gè)節(jié)點(diǎn)是否已經(jīng)被查找到,并構(gòu)造成樹(shù)過(guò) } 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);//初始化赫夫曼樹(shù) void create_H(Hffmantree* H, int n);//創(chuàng)建赫夫曼樹(shù) void traverse_H(Hffmantree* H, int n);//遍歷輸出赫夫曼樹(shù)int main() {int n;printf("請(qǐng)輸入該赫夫曼樹(shù)的葉子節(jié)點(diǎn)個(gè)數(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;}//存入赫夫曼樹(shù)節(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);//輸出一次初始化的赫夫曼樹(shù)create_H(H, n);traverse_H(H, n);//輸出一次構(gòu)造好的赫夫曼樹(shù) }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值不合理,用一個(gè)for循環(huán)找到第一個(gè)為被查找到過(guò)的節(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;//改寫(xiě)flag為1,標(biāo)志該結(jié)點(diǎn)已被查找過(guò)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位開(kāi)始創(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;//存儲(chǔ)“根節(jié)點(diǎn)”的權(quán)重H[i].lchild = a;//存儲(chǔ)“根節(jié)點(diǎn)”的左孩子下標(biāo)H[i].rchild = b;//存儲(chǔ)“根節(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)前的赫夫曼樹(shù):\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"); }思路
-------------------------------從一個(gè)博主那里順來(lái)的百度圖片(感謝萬(wàn)分)--------------------------------------
如圖所示
大致思路:
將所有具有權(quán)重的葉子節(jié)點(diǎn)一字排開(kāi),在其中找到的權(quán)重最小的兩個(gè)葉子節(jié)點(diǎn)借助一個(gè)新的節(jié)點(diǎn)(根)鏈接成一棵樹(shù)(一般兩個(gè)節(jié)點(diǎn)中權(quán)重小的為左孩子,更大的為右孩子),這個(gè)根的權(quán)重就等于那兩個(gè)葉子節(jié)點(diǎn)的權(quán)重之和,然后再將這個(gè)根放在那一堆還未選出的葉子節(jié)點(diǎn)中進(jìn)行比較,再找到其中兩個(gè)最小的節(jié)點(diǎn)鏈接成一棵樹(shù),反復(fù)重復(fù)上述操作,直到構(gòu)建成一棵完整的赫夫曼樹(shù)(本質(zhì)上就上讓權(quán)重越大的葉子節(jié)點(diǎn)越靠近根節(jié)點(diǎn))
構(gòu)造步驟
借助一個(gè)結(jié)構(gòu)體數(shù)組存儲(chǔ)這個(gè)赫夫曼樹(shù),結(jié)構(gòu)體中包含權(quán)重,雙親的數(shù)組下標(biāo),左孩子的數(shù)組下標(biāo),右孩子的數(shù)組下標(biāo),一個(gè)標(biāo)志節(jié)點(diǎn)是否已被建造的flag(直接用雙親判斷也可以);
1.先初始化這個(gè)赫夫曼樹(shù):
將結(jié)構(gòu)體中所有的數(shù)據(jù)賦予0值。
2.創(chuàng)造赫夫曼樹(shù)(借助一個(gè)函數(shù)尋找最小權(quán)重的兩個(gè)節(jié)點(diǎn)):
從第n+1個(gè)數(shù)組位置開(kāi)始創(chuàng)建用來(lái)鏈接兩個(gè)葉子節(jié)點(diǎn)的“根節(jié)點(diǎn)”,在創(chuàng)建每一個(gè)“根節(jié)點(diǎn)”時(shí),要,將兩個(gè)葉子節(jié)點(diǎn)的雙親的數(shù)組下標(biāo)存入(也就是當(dāng)前這個(gè)根節(jié)點(diǎn)的下標(biāo)),要存儲(chǔ)“根節(jié)點(diǎn)”的權(quán)重,左右孩子的數(shù)組下標(biāo);在尋找最小權(quán)重的兩個(gè)葉子節(jié)點(diǎn)的函數(shù)中,每找到一個(gè)節(jié)點(diǎn)時(shí),記得將這個(gè)節(jié)點(diǎn)的flag值改為1,便于后續(xù)查找剩余節(jié)點(diǎn)中的最小節(jié)點(diǎn)時(shí),可以跳過(guò)這個(gè)節(jié)點(diǎn)。
3.遍歷輸出赫夫曼樹(shù)
很簡(jiǎn)單,直接將數(shù)組的每一位輸出即可。
總結(jié)
- 上一篇: 华为无线之充电小结
- 下一篇: JAVA毕业设计酒店管理系统设计与实现计