前言:哈夫曼樹(最優二叉樹)的筆記
到這里樹的基本相關的數據結構都擼了一遍,接下來一個星期繼續來擼圖的結構,之前沒有時間,現在有時間都來寫一遍,為什么要寫呢,我自己感覺其實還是跟逆向相關,因為有些東西數據結構會占比多,所以對經典的數據結構的了解,同樣對逆向的水平會有長進!
哈夫曼樹的構建比較簡單,不過我查了相關的資料都是涉及到什么二叉堆的,我沒有學過,按照自己的理解來創建了一棵哈夫曼樹,同樣能實現構建哈夫曼樹和權值的計算
思路:
1、在兩個節點每次創建父節點的時候,都事先先進行排序一次,然后再進行闖將
2、創建完的父節點重新插入到節點數組中,然后一次進行這兩步即可
對於權值的計算,其實主要需要知道路徑的條數(其實也就是樹的高度),並且權值的計算都是針對於葉子節點的,所以我的想法就是遞歸把計算計算出來即可,然后通過標志來區分是否是葉子節點即可進行相關樹的權值
代碼實現如下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define OK 1
#define ERROR 0
/*
@author zpchcbd
@time 2022.4.07
實現哈夫曼樹
*/
typedef int ElemType;
typedef int Status;
typedef struct _TreeNode{
struct _TreeNode* pLeftTreeNode;
struct _TreeNode* pRightTreeNode;
ElemType weightValue;
ElemType flag;
struct _TreeNode* parent;
}TreeNode, *PTreeNode;
// 排序
void sortNodeArray(TreeNode* iArray[], int m)
{
int i = 0, j = 0;
TreeNode* tmp = 0;
for (i = 0;i<m-1;i++)
{
for (j = 0; j<m-i-1; j++)
{
if (iArray[j]->weightValue < iArray[j+1]->weightValue)
{
tmp = iArray[j];
iArray[j] = iArray[j + 1];
iArray[j + 1] = tmp;
}
}
}
for (i = 0; i< m; i++)
printf("%d ", iArray[i]->weightValue);
printf("\n");
}
// 計算樹中的帶權路徑長度
ElemType getAllWeight(TreeNode* pTreeNode, ElemType iHeight)
{
int iLength = 0;
if (pTreeNode!=NULL)
{
printf("%d ", pTreeNode->weightValue);
iLength += getLength(pTreeNode->pLeftTreeNode, iHeight + 1);
iLength += getLength(pTreeNode->pRightTreeNode, iHeight + 1);
if (pTreeNode->flag == 1 || pTreeNode->flag == 0)
{
iLength += pTreeNode->weightValue*iHeight;
}
}
return iLength;
}
TreeNode* createHuffmanTreeNode(TreeNode* pT1, TreeNode* pT2)
{
TreeNode* pTreeNode = NULL;
if (pTreeNode == NULL)
{
pTreeNode = malloc(sizeof(TreeNode));
pTreeNode->pLeftTreeNode = NULL;
pTreeNode->pRightTreeNode = NULL;
pTreeNode->weightValue = 0;
pTreeNode->flag = -1;
if (pTreeNode == NULL)
return NULL;
}
if (pT1->weightValue < pT2->weightValue)
{
pTreeNode->pLeftTreeNode = pT1;
pTreeNode->pRightTreeNode = pT2;
if (pT1->flag == 2)
pT1->flag = 0;
if (pT2->flag == 2)
pT2->flag = 1;
}
else
{
pTreeNode->pRightTreeNode = pT2;
pTreeNode->pLeftTreeNode = pT1;
if (pT2->flag == 2)
pT2->flag = 0;
if (pT1->flag == 2)
pT1->flag = 1;
}
pT1->parent = pTreeNode;
pT2->parent = pTreeNode;
// 新建的節點的value是左節點右節點的value之和
pTreeNode->weightValue = pT1->weightValue + pT2->weightValue;
return pTreeNode;
}
int main()
{
TreeNode* pTreeNode = NULL;
TreeNode* pTreeNodeArray[7] = { 0 };
ElemType pNodeValue[5] = { 1,2,3,4,5 };
int i, j;
// 初始化完降序排列的棧,該棧中保存的都是TreeNode節點
for (i = 0;i<5;i++)
{
pTreeNodeArray[i] = malloc(sizeof(TreeNode));
pTreeNodeArray[i]->weightValue = pNodeValue[i];
pTreeNodeArray[i]->pLeftTreeNode = NULL;
pTreeNodeArray[i]->pRightTreeNode = NULL;
pTreeNodeArray[i]->flag = 2;
}
sortNodeArray(pTreeNodeArray, i);
for (j = 4; j >= 0; j--)
{
pTreeNode = createHuffmanTreeNode(pTreeNodeArray[j], pTreeNodeArray[j - 1]);
pTreeNodeArray[j] = pTreeNodeArray[j - 1] = NULL;
pTreeNodeArray[j - 1] = pTreeNode;
sortNodeArray(pTreeNodeArray, j);
if (pTreeNodeArray[1] == NULL)
break;
}
printf("=======preOrer=======\n");
//preOrder(pTreeNodeArray[0]);
printf("--%d--", getAllWeight(pTreeNodeArray[0], 0));
return 0;
}
測試數據:ElemType pNodeValue[5] = { 1,2,3,4,5 };