1. 程式人生 > >帶權路徑長度 層次遍歷

帶權路徑長度 層次遍歷

思路:層次遍歷

帶權路徑長度:結點具有權值,從該結點到根之間的路徑長度乘以結點的權值,就是該結點的帶權路徑長度。

葉子結點的帶權路徑長度:結點到根之間的路徑長度(所在層數-1)乘以結點的權值。

樹的帶權路徑長度(WPL):樹的所有葉子結點的帶權路徑長度之和。

樹的帶權路徑長度記為WPL = (W1*L1 + W2*L2 + W3*L3 + ... + Wn*Ln),N個權值Wi(i = 1, 2, ...n)構成一棵有N個葉結點的二叉樹,相應的葉結點的路徑長度為Li(i = 1, 2, ...n)。

隨便複習哈夫曼樹:

可以證明哈夫曼樹的WPL是最小的。WPL是衡量一個帶權二叉樹優劣的關鍵。

無論如何,對於n個帶權節點,可以用他們作為葉節點構造出一顆最小WPL值得樹,並稱滿足這個條件的二叉樹為哈夫曼樹。

【例】給定4個葉子結點a,b,c和d,分別帶權7,5,2和4。構造如下圖所示的三棵二叉樹(還有許多棵),它們的帶權路徑長度分別為:

(a)WPL = 7 * 2 + 5 * 2 + 2 * 2 + 4 * 2 = 36

(b)WPL = 7 * 3 5 * 3 2 * 1  4 * 2 = 46

(c)WPL = 7 * 1  5 * 2 2 * 3 4 * 3 = 35

其中(c)樹的WPL最小,可以驗證,它就是哈夫曼樹。

#include <iostream>
#include <queue>
using namespace std;

class TreeNode{
private:
	char val;
	TreeNode* left;
	TreeNode* right;
public:
	//二叉樹的初始化函式 
	TreeNode* Create_TreeNode(){
		TreeNode* T = new TreeNode;
		char ch;
		cin >> ch;
		if (ch == '#'){                                                  //“#”是結束標誌 
			T = NULL;
		}else{
			T->val = ch;                                               //對當前結點初始化 
			T->left = Create_TreeNode();                            //遞迴構造左子樹 
			T->right = Create_TreeNode();                            //遞迴構造右子樹 
		}
		return T;
	}

	int WPL(TreeNode* root) {
		queue<TreeNode*> que;//處理資料佇列  
		vector<int> temp;// 儲存每一層資料  
		 
		TreeNode* last = root;
		TreeNode* nLast = root;
		que.push(root);
		int level = 1;	//level代表層數 
		int sum = 0; //帶權路徑長度之和    
		while (!que.empty()){
			TreeNode* proot = que.front();
			que.pop();
			temp.push_back(proot->val);
			if (proot->left){ //左孩子非空入隊
				que.push(proot->left);
				nLast = proot->left;
			}
			if (proot->right){ //右孩子非空入隊
				que.push(proot->right);
				nLast = proot->right;
			}
			if (proot == last){ //隊頭指標是該層最後一個結點時 
				level++;//層數加一
				last = nLast;//最後一個結點指標下移到下一層的最後一個結點 
				temp.clear();
			}
			if (proot->left == NULL && proot->right == NULL){
				int weight = proot->val - '0';
				sum += (level - 1)*weight; //層數level,該層的每個葉節點的帶權路徑長度 = (level - 1)*weight
			}
		}
		return sum;
	}
};
int main()
{
	cout << "請初始化二叉樹:" << endl;
	TreeNode Tree;
	TreeNode* T1 = Tree.Create_TreeNode();

	cout << "葉子節點的帶權路徑之和為:" << endl;
	int wpl = Tree.WPL(T1);
	cout << wpl << endl;
	system("pause");
	return 0;
}