#include<iostream>
using namespace std;
int m = 0;
typedef struct {
	int weight;
	int jilu;//记录编码的权值
	int parent, lchild, rchild;
}HTNode, *HuffmanTree; //动态分配数组存储哈夫曼树
typedef char *HuffmanCode; //动态分配数组存储哈夫曼编码表

void Select(HuffmanTree HT, int n,int &s1,int &s2) {
	int i, j;
	for (i = 1; i <= n; i++)
	if (!HT[i].parent){ s1 = i; break; }
	for (j = i + 1; j <= n; j++)
	if (!HT[j].parent){ s2 = j; break; }
	for (i = 1; i <= n; i++)
	if ((HT[s1].weight>HT[i].weight) && (!HT[i].parent) && (s2 != i))s1 = i;
	for (j = 1; j <= n; j++)
	if ((HT[s2].weight>HT[j].weight) && (!HT[j].parent) && (s1 != j))s2 = j;
}

void HuffmanCoding(HuffmanTree &HT, HuffmanCode HC[],int n) {
	// w存放n个字符的权值(均>0),构造哈夫曼树HT,
	// 并求出n个字符的哈夫曼编码HC
	int i, j,s1,s2;
	char *cd;
	int p;
	int cdlen;
	if (n <= 1) return;
	m = 2 * n - 1;
	HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode)); // 0号单元未用
	for (i =1; i <= m; i++) { //初始化
		HT[i].parent = 0;HT[i].lchild = 0;HT[i].rchild = 0;
	}
	for (i = 1; i <= n; i++) { //输入权值
		cin>>HT[i].weight;
		HT[i].jilu = HT[i].weight;
	}
	for (i = n + 1; i <= m; i++) { // 建哈夫曼树
		// 在HT[1..i-1]中选择parent为0且weight最小的两个结点,
		// 其序号分别为s1和s2。
		Select(HT, i - 1,s1,s2);
		HT[s1].parent = i; HT[s2].parent = i;
		if (HT[s1].weight<=HT[s2].weight)
		{
			HT[i].lchild = s1; HT[i].rchild = s2;
		}
		else{HT[i].lchild = s2; HT[i].rchild = s1;}
		HT[i].weight = HT[s1].weight + HT[s2].weight;
	}
	printf(" 下标  权值  父亲  左孩子  右孩子");
	for (j = 1; j <= i-1; j++)
	{
		printf("\n[%2d]%6d%6d%6d%6d", j, HT[j].weight, HT[j].parent, HT[j].lchild, HT[j].rchild);
	}

	//------无栈非递归遍历哈夫曼树,求哈夫曼编码
	cd = (char *)malloc(n*sizeof(char)); // 分配求编码的工作空间
	p = m; cdlen = 0;
	for (i = 1; i <= m; ++i) // 遍历哈夫曼树时用作结点状态标志
		HT[i].weight = 0;
	while (p) {
		if (HT[p].weight == 0) { // 向左
			HT[p].weight = 1;
			if (HT[p].lchild != 0) { p = HT[p].lchild; cd[cdlen++] = '0'; }
			else if (HT[p].rchild == 0) { // 登记叶子结点的字符的编码
				HC[p] = (char *)malloc((cdlen + 1) * sizeof(char));
				cd[cdlen] = '\0'; strcpy(HC[p], cd); // 复制编码(串)
			}
		}
		else if (HT[p].weight == 1) { // 向右
			HT[p].weight = 2;
			if (HT[p].rchild != 0) { p = HT[p].rchild; cd[cdlen++] = '1'; }
		}
		else { // HT[p].weight==2,退回退到父结点,编码长度减1
			HT[p].weight = 0; p = HT[p].parent; --cdlen;
		}
	}
} // HuffmanCoding
void main() {
	HuffmanTree HT;
	HuffmanCode *HC;
	int n, i;
	cout << "请输入叶子结点个数:" << endl;
	cin >> n;
	HC = (HuffmanCode *)malloc(n*sizeof(HuffmanCode));
	cout << "请输入叶子结点的权值:" << endl;
	HuffmanCoding(HT, HC,n);
	for (i = 1; i <= n; i++)
	{
		printf("\n%2d编码为:%s", HT[i].jilu, HC[i]);
	}
	getchar();
}