#任务描述#
(1)采用二叉链表结构建立二叉树;
(2)二叉树的先序、中序、后序和层序遍历;
(3)求二叉树的深度和叶子结点个数;
(4)哈夫曼编码;
一、建立二叉链表
首先定义结点BiTNode和二叉树BiTree
typedef char TElemType;
typedef struct BiTNode
{
TElemType data;
struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
采用先序的方式创建二叉树(二叉链表结构)
void CreateBiTree(BiTree &T)
{
TElemType ch;
cin >> ch;
if(ch == '#')
T = NULL;
else
{
T = new BiTNode;
T->data = ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
此函数中, “#”表示空结点。在调用CreateBiTree建立二叉树时,应该按照先序遍历顺序依次输入二叉树结点值(包括空结点)。例如,要创建以下二叉树,应输入“ABD##E##C##”。
二、遍历二叉树
// 先序遍历二叉树T
void PreOrderTraverse(BiTree T)
{
if(T)
{
cout << " " << T->data << " ";
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
// 中序遍历二叉树T
void InOrderTraverse(BiTree T)
{
if(T)
{
InOrderTraverse(T->lchild);
cout << " " << T->data << " ";
InOrderTraverse(T->rchild);
}
}
// 后序遍历二叉树T
void PostOrderTraverse(BiTree T)
{
if(T)
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
cout << " " << T->data << " ";
}
}
// 层序遍历二叉树T
void LevelOrderTraverse(BiTree T)
{
queue<BiTree> Tlist;
if(!T)
return;
else{
Tlist.push(T);
while(!Tlist.empty())
{
if(T->lchild)
Tlist.push(T->lchild);
if(T->rchild)
Tlist.push(T->rchild);
cout << " " << T->data << " ";
Tlist.pop();
T = Tlist.front();
}
}
}
三、计算二叉树的深度
计算二叉树T的深度------非递归算法
int depth(BiTree T)
{
int d = 0;
while(T)
{
d++;
if(T->lchild) //l和r所有可能的情况:lr都空,lr都不空,l空r不空,l不空r空
//在前两种情况里无论区l还是r来计算高度效果一样,当l空r不空时,经过if语句取到了r,当l不空r空时,if语句取到了l
//这样就可以保证height始终取到树最大的层数
T = T->lchild;
else
T = T->lchild;
}
return d;
}
计算二叉树T的深度------递归算法
int Depth(BiTree T)
{
if(!T)
return 0;
else
{
int m = Depth(T->lchild);
int n = Depth(T->rchild);
if(m > n )
return (m + 1);
return (n + 1);
}
}
计算二叉树T的叶子结点的总数
int LeafNum(BiTree T)
{
int num = 0;
queue<BiTree> Tlist;
if(!T)
return num;
else
{
Tlist.push(T);
while(!Tlist.empty())
{
if(T->lchild)
Tlist.push(T->lchild);
if(T->rchild)
Tlist.push(T->rchild);
if(T->rchild && T->lchild)
num++;
Tlist.pop();
T = Tlist.front();
}
}
return num;
}
四、哈弗曼编码
树的带权路径长度为树中所有叶子结点的带权路径长度之和,通常记作WPL。假设有m个权值,可以构造一棵含n个叶子结点的二叉树,每个叶子结点的权值对应这m个权值,则其中WPL最小的二叉树称作哈夫曼树(最优二叉树)。哈夫曼树没有度为1的结点。一棵有n个叶子结点的哈夫曼树有2n-1个结点。
首先定义Huffman树结点HTNode和Huffman树HuffmanTree
typedef struct
{
int weight;
int parent,lchild, rchild;
}HTNode, *HuffmanTree;
然后创建Select函数,Select函数用于从森林中选取两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树。
void Select(HuffmanTree HT, int n, int& s1, int& s2)
{
int min;
for (int i = 1; i <= n; i++) //找到第一个parent域为0的下标作为初始min
if (HT[i].parent == 0)
{
min = i;
break;
}
for (int i = min + 1; i <= n; i++)
if (HT[i].parent == 0 && HT[i].weight < HT[min].weight)
min = i;
s1 = min;
for (int i = 1; i <= n; i++)
if (HT[i].parent == 0 && i != s1) //找到与s1相等的第一个parent域为0的下标作为s2的初始min
{
min = i;
break;
}
for (int i = min + 1; i <= n; i++)
{
if (HT[i].parent == 0 && HT[i].weight < HT[min].weight && i != s1)
min = i;
}
s2 = min;
}
建立哈夫曼树HT
void CreateHuffmanTree(HuffmanTree& HT, int n) //n是要进行哈夫曼编码的元素个数
{
if(n <= 1)
return;
int m = 2 * n - 1; //m是哈夫曼树HT的结点数
HT = new HTNode[m + 1]; //由于0号单元不使用,因此为HT申请m+1个结点空间
for (int i = 1; i <= m; ++i) //初始化所有结点
{
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
cout << "依次输入元素的权值: "; //根据给定的n个权值,构造n棵只有根结点的二叉树,这n棵二叉树构成一个森林,这个森林最终会成为哈夫曼树HF
for (int i = 1; i <= n; ++i)
cin >> HT[i].weight;
for (int i = n + 1; i <= m; ++i) //开始构建哈夫曼树
{
int s1, s2;
Select(HT, i - 1, s1, s2); //在下标为1到i-1的范围内找到l两个双亲域均为0且权值最小的结点,并返回它们在HT中的序号s1和s2,其中s1的权值小于s2的权值
HT[i].weight = HT[s1].weight + HT[s2].weight; //i的权重是s1和s2的权重之和
HT[s1].parent = i;
HT[s2].parent = i;
HT[i].lchild = s1;
HT[i].rchild = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight;
}
}
生成哈夫曼编码
typedef char **HuffmanCode;
void CreateHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n)
{
HC = new char*[n + 1];
char* code = new char[n]; //使用c字符串来存储一个哈弗曼编码,0号单元未使用
code[n - 1] = '\0';
for (int i = 1; i <= n; ++i)
{
int start = n - 1;
int c = i;
int f = HT[i].parent;
while (f != 0)
{
--start;
if (HT[f].lchild == c)
code[start] = '0';
else
code[start] = '1';
c = f;
f = HT[f].parent; //继续向上回溯
}
HC[i] = new char[n - start];
strcpy(HC[i], &code[start]); //复制字符串
}
delete code; //释放辅助空间
}
五、总结
#include <iostream>
#include <queue>
#include <string.h>
using namespace std;
typedef char TElemType;
typedef struct BiTNode
{
TElemType data;
struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
void CreateBiTree(BiTree &T)
{
TElemType ch;
cin >> ch;
if(ch == '#')
T = NULL;
else
{
T = new BiTNode;
T->data = ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
void PreOrderTraverse(BiTree T)
{
if(T)
{
cout << " " << T->data << " ";
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
void InOrderTraverse(BiTree T)
{
if(T)
{
InOrderTraverse(T->lchild);
cout << " " << T->data << " ";
InOrderTraverse(T->rchild);
}
}
void PostOrderTraverse(BiTree T)
{
if(T)
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
cout << " " << T->data << " ";
}
}
void LevelOrderTraverse(BiTree T)
{
queue<BiTree> Tlist;
if(!T)
return;
else{
Tlist.push(T);
while(!Tlist.empty())
{
if(T->lchild)
Tlist.push(T->lchild);
if(T->rchild)
Tlist.push(T->rchild);
cout << " " << T->data << " ";
Tlist.pop();
T = Tlist.front();
}
}
}
int depth(BiTree T)
{
int d = 0;
while(T)
{
d++;
if(T->lchild)
T = T->lchild;
else
T = T->lchild;
}
return d;
}
int Depth(BiTree T)
{
if(!T)
return 0;
else
{
int m = Depth(T->lchild);
int n = Depth(T->rchild);
if(m > n)
return (m + 1);
return (n + 1);
}
}
int LeafNum(BiTree T)
{
int num = 0;
queue<BiTree> Tlist;
if(!T)
return num;
else
{
Tlist.push(T);
while(!Tlist.empty())
{
if(T->lchild)
Tlist.push(T->lchild);
if(T->rchild)
Tlist.push(T->rchild);
if(T->rchild && T->lchild)
num++;
Tlist.pop();
T = Tlist.front();
}
}
return num;
}
/*哈弗曼编码*/
typedef struct
{
int weight;
int parent,lchild, rchild;
}HTNode, *HuffmanTree;
void Select(HuffmanTree HT, int n, int& s1, int& s2)
{
int min;
for (int i = 1; i <= n; i++) //找到第一个parent域为0的下标作为初始min
if (HT[i].parent == 0)
{
min = i;
break;
}
for (int i = min + 1; i <= n; i++)
if (HT[i].parent == 0 && HT[i].weight < HT[min].weight)
min = i;
s1 = min;
for (int i = 1; i <= n; i++)
if (HT[i].parent == 0 && i != s1) //找到与s1相等的第一个parent域为0的下标作为s2的初始min
{
min = i;
break;
}
for (int i = min + 1; i <= n; i++)
{
if (HT[i].parent == 0 && HT[i].weight < HT[min].weight && i != s1)
min = i;
}
s2 = min;
}
void CreateHuffmanTree(HuffmanTree& HT, int n) //n是要进行哈夫曼编码的元素个数
{
if(n <= 1)
return;
int m = 2 * n - 1; //m是哈夫曼树HT的结点数
HT = new HTNode[m + 1]; //由于0号单元不使用,因此为HT申请m+1个结点空间
for (int i = 1; i <= m; ++i) //初始化所有结点
{
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
cout << "依次输入元素的权值: "; //根据给定的n个权值,构造n棵只有根结点的二叉树,这n棵二叉树构成一个森林,这个森林最终会成为哈夫曼树HF
for (int i = 1; i <= n; ++i)
cin >> HT[i].weight;
for (int i = n + 1; i <= m; ++i)
{
int s1, s2;
Select(HT, i - 1, s1, s2); //在下标为1到i-1的范围内找到l两个双亲域均为0且权值最小的结点,并返回它们在HT中的序号s1和s2,其中s1的权值小于s2的权值
HT[i].weight = HT[s1].weight + HT[s2].weight; //i的权重是s1和s2的权重之和
HT[s1].parent = i;
HT[s2].parent = i;
HT[i].lchild = s1;
HT[i].rchild = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight;
}
}
typedef char **HuffmanCode;
void CreateHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n)
{
HC = new char*[n + 1];
char* code = new char[n];
code[n - 1] = '\0';
for (int i = 1; i <= n; ++i)
{
int start = n - 1;
int c = i;
int f = HT[i].parent;
while (f != 0)
{
--start;
if (HT[f].lchild == c)
code[start] = '0';
else
code[start] = '1';
c = f;
f = HT[f].parent;
}
HC[i] = new char[n - start];
strcpy(HC[i], &code[start]);
}
delete code;
}
int main()
{
BiTree T = new BiTNode;
cout << "按先序遍历顺序依次输入二叉树结点值('#'表示空结点):";
CreateBiTree(T);
cout << "二叉树先序遍历结果:";
PreOrderTraverse(T);
cout << endl;
cout << "二叉树中序遍历结果:";
InOrderTraverse(T);
cout << endl;
cout << "二叉树后序遍历结果:";
PostOrderTraverse(T);
cout << endl;
cout << "二叉树层序遍历结果:";
LevelOrderTraverse(T);
cout << endl;
cout << "该二叉树的深度为(非递归函数): " << depth(T) << endl;
cout << "该二叉树的深度为(递归函数): " << Depth(T) << endl;
cout << "该二叉树的叶子结点个数为: " << LeafNum(T) << endl;
HuffmanTree HT = new HTNode;
cout << "输入要进行哈夫曼编码的元素个数: ";
int n;
cin >> n;
CreateHuffmanTree(HT, n);
HuffmanCode HC = new char*[n + 1];
CreateHuffmanCode(HT, HC, n);
cout << "元素权值对应的哈夫曼编码如下:" << endl;
for(int i = 1; i <= n; i++)
cout << HT[i].weight << " : " << HC[i] << endl;
return 0;
}
运行结果: