閱讀104 返回首頁    go 阿裏雲 go 技術社區[雲棲]


最優二叉樹算法

練習做一下構造最優二叉樹的算法,不過如何計算WPL呢?

本次未能實現,希望懂的人可以幫我解決一下這個問題,不勝感激!

//
// 頭文件:HuffmanTree.h

//
// 葉子結點的最大數量
#define LEAVES_COUNT 4

//
// 二叉樹的最大結點總數
#define NODES_COUNT (2 * LEAVES_COUNT - 1)

//
// 哈夫曼樹的結點結構體
typedef struct tagHuffmanTreeNode
{
	float weight;  // 權值,假設權值都是大於零的值
	int parent;    // 指示雙親
	int lchild;    // 指示左孩子
	int rchild;    // 指示右孩子
}HuffmanNode;

//
// 哈夫曼樹定義為二維數組
typedef HuffmanNode HuffmanTree[NODES_COUNT];


//
// 構造一棵哈夫曼樹
void CreateHuffmanTree(HuffmanTree tree);

//
// 初始化
void InitHuffmanTree(HuffmanTree tree);

//
// 輸入葉子的權值
void InputWeightsOfLeaves(HuffmanTree tree);

//
// 選擇兩個權最小的結點生成新的結點
void SelectMin(HuffmanTree tree, int maxValue, int *left, int *right);

//
// 計算哈夫曼樹的最小帶權路徑長度之和
int ComputeWPL(HuffmanTree tree);

//
// 測試哈夫曼樹的構造,譯碼
// HuffmanTree.c

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

#include "HuffmanTree.h"

int main()
{

	HuffmanTree tree;

	// 構造哈夫曼樹
	CreateHuffmanTree(tree);

	printf("WPL=%d\n", ComputeWPL(tree));

	return 0;
}

//
// 構造一棵哈夫曼樹
void CreateHuffmanTree(HuffmanTree tree)
{
	int i;
	int left, right;
 
	InitHuffmanTree(tree);      // 初始化

	printf("輸入%d個結點值:\n", LEAVES_COUNT);
	InputWeightsOfLeaves(tree); // 輸入葉子權值至T[0..n-1]的weight域  

	// 共進行n-1次合並,新結點依次存於T[i]中  
    for (i = LEAVES_COUNT; i < NODES_COUNT; i++)
    {
		// 在tree中0~i-1中選擇最小的兩個根結點
		SelectMin(tree, i - 1, &left, &right);

		// 在i個結點作為新合成結點的雙親
		tree[left].parent = i;
		tree[right].parent = i;
		tree[i].lchild = left;  // 最小權的根結點是新結點的左孩子
		tree[i].rchild = right; // 次小權的根結點是新結點的右孩子 

		// 新結點的權值
		tree[i].weight = tree[left].weight + tree[right].weight;
    }

}


//
// 初始化
// 因為C語言數組的下界為0,故用-1表示空指針。樹中某結點的lchild、rchild和parent不等於-1時,
// 它們分別是該結點的左、右孩子和雙親結點在向量中的下標。這裏設置parent域有兩個作用:其一是使查找
// 某結點的雙親變得簡單;其二是可通過判定parent的值是否為-1來區分根與非根結點。
//  將T[0..m-1]中2n-1個結點裏的三個指針均置為空(即置為-1),權值置為0。
void InitHuffmanTree(HuffmanTree tree)
{
	int i = 0;

	for (i = 0; i < NODES_COUNT; i++)
	{
		tree[i].lchild = -1;
		tree[i].rchild = -1;
		tree[i].parent = -1;
		tree[i].weight = 0;
	}
}

//
// 輸入葉子的權值
// 讀人n個葉子的權值存於向量的前n個分量(即T[0..n-1])中。它們是初始森林中n個孤立的根結點上的權值。
void InputWeightsOfLeaves(HuffmanTree tree)
{
     char ch;
	 int i;

	 for (i = 0; i < LEAVES_COUNT; i++)
	 {
		 scanf("%c", &tree[i].weight);
	 }
}

//
// 選擇兩個權最小的結點生成新的結點
void SelectMin(HuffmanTree tree, int maxValue, int *left, int *right)
{
	int i, j;
	int const MAX_VALUE = 10000;
    int m1, m2;

	for (i = 0; i < maxValue; i++)
	{
		m1 = m2 = MAX_VALUE;
		*left = 0;
		*right = 0;

		for (j = 0; j < LEAVES_COUNT + 1; j++)
		{
			if (tree[j].weight < m1 && tree[i].parent == -1) // 要求此結點還沒有構造
			{
				m2 = m1; // 較大者給m2
				*right = *left;

				m1 = tree[j].weight; // 取較小者
				*left = j;
			}
			else if (tree[j].weight < m2 && tree[i].parent == -1)
			{
				m2 = tree[j].weight;
                *right = j;
			}
		}
	}
}

//
// 計算哈夫曼樹的最小帶權路徑長度之和
int ComputeWPL(HuffmanTree tree)
{
	int i = 0;
	int wpl = 0;

    for (i = 0; i < NODES_COUNT; i++)
    {
         if (IsLeaf(tree[i]))
         {
			 wpl += tree[i].weight * (i + 1); // 這裏不正確,該如何獲取結點所有的層數呢?
         }
    }

	return wpl;
}

//
// 判斷是否為葉子結點
int IsLeaf(HuffmanNode node)
{
    return node.lchild == -1 && node.rchild == -1;
}


最後更新:2017-04-03 18:51:56

  上一篇:go 一笑泯恩仇:蓋茨回憶喬布斯
  下一篇:go Android遊戲開發之橫豎屏的切換