文章目录
一、二叉树的创建和遍历
(一)算法设计
1、数据结构
typedef struct btnode { // 二叉树节点结构体
ElemType element;
struct btnode* lChild;
struct btnode* rChild;
}BTNode;
分析:设计了二叉树节点结构体,内含三个成员变量,本节点的关键字值element,左孩子和有孩子节点的地址lChild 和 rChild。
2、算法流程图绘制
3、模块设计
(二)算法实现与分析
1、先序构建二叉树
BTNode* PreCreateBt(BTNode* t) {
char c;
c = getchar();
if (c == '#') { // 输入#表示此节点没有孩子
t = NULL;
}
else {
t = (BTNode*)malloc(sizeof(BTNode));
t->element = c; //构造根结点
t->lChild = PreCreateBt(t->lChild); //构造左子树
t->rChild = PreCreateBt(t->rChild); //构造右子树
}
return t;
}
算法分析:采用递归算法,先构造根节点,再构造左孩子,再构造右孩子,依次递归。
时间复杂度:O(n)
2、先序遍历 VLR
void PreOrderTransverse(BTNode* t) {
if (t == NULL) {
return;
}
printf("%c", t->element); // 先序遍历根结点并输出
PreOrderTransverse(t->lChild); // 先序遍历左子树
PreOrderTransverse(t->rChild); // 先序遍历右子树
}
算法分析:采用递归算法,先遍历根节点,再遍历左孩子,再遍历右孩子。
时间复杂度:O(n)
3、中序遍历 LVR
void InOrderTransverse(BTNode* t) {
if (t == NULL) {
return;
}
InOrderTransverse(t->lChild); // 中序遍历根结点的左子树
printf("%c", t->element); // 打印输出根结点
InOrderTransverse(t->rChild); // 中序遍历根结点的右子树
}
算法分析:采用递归算法,先遍历左孩子,再遍历根节点并输出,再遍历右孩子。
时间复杂度:O(n)
4、后序遍历 LRV
void PostOrderTransverse(BTNode* t) {
if (t == NULL) {
return;
}
PostOrderTransverse(t->lChild); // 后序遍历根结点的左子树
PostOrderTransverse(t->rChild); // 后序遍历根结点的右子树
printf("%c", t->element); // 最后打印输出根结点
}
算法分析:采用递归算法,先遍历左孩子,再遍历右孩子,再遍历根节点并输出。
时间复杂度:O(n)
(三)实验结果
二、二叉树求解
(一)算法设计
1、数据结构
typedef struct btnode {
ElemType element;
struct btnode* lChild;
struct btnode* rChild;
}BTNode;
分析:设计了二叉树节点结构体,内含三个成员变量,本节点的关键字值element,左孩子和有孩子节点的地址lChild 和 rChild。如果节点的element为 ’#’ 则表示该节点为空。
2、算法流程图绘制
3、模块设计
(二)算法实现与分析
1、求二叉树结点个数
//求二叉树结点个数
int Size(BTNode* t) {
if (t == NULL) return 0;
return Size(t->lChild) + Size(t->rChild) + 1;
}
分析:如果为空树,返回二叉树结点数为0;不是空树,则依次递归本节点的左孩子和右孩子,返回
返回左子树点数+右子树节点数+1;即可求得二叉树节点的数量。
时间复杂度:O(n)
2、求二叉树叶子结点数
//求二叉树叶子结点个数
int Leaf(BTNode* t) {
if (t == NULL) return 0;
if ((t->lChild == NULL) && (t->rChild == NULL)) return 1;
return Leaf(t->lChild) + Leaf(t->rChild);
}
分析:如果为空树,返回叶子结点数为0;不是空树且当前节点的左孩子和右孩子均为空节点,返回1;
否则计算左子树的叶子节点数与右子树叶子节点数之和并返回;即可求得二叉树叶子节点的数量。
时间复杂度:O(n)
3、求二叉树的高度
//求二叉树的高度
int Depth(BTNode* t) {
if (t == NULL) return 0;
else return 1 + std::max(Depth(t->lChild), Depth(t->rChild));
}
分析:如果当前节点为空,返回树的高度为0;否则递归1+左孩子和右孩子中较大的树的高度并返回。
时间复杂度:O(n)
4、求交换二叉树所有左右子树
//交换二叉树所有子树
void Swap(BTNode* t) {
if (t) {
BTNode* temp = t->lChild;
t->lChild = t->rChild;
t->rChild = temp;
Swap(t->lChild);
Swap(t->rChild);
}
分析:采用递归算法,如果当前节点不为空,则将本节点的左右孩子交换,依次递归调用左孩子和右孩子,即可完成二叉树所有子树的交换。
时间复杂度:O(n)
(三)实验结果
三、哈夫曼树
(一)算法设计
1、数据结构
typedef struct hfmTNode {
ElemType element; //结点的数据域
int w; //结点的权值
struct hfmTNode* lChild; //结点的左孩子指针
struct hfmTNode* rChild; //结点的右孩子指针
}HFMTNode;
分析:创建哈夫曼树节点结构体,内含4个成员变量,分别为节点的数据域,节点的权值,节点的左孩子地址和节点的右孩子地址。
2、算法流程图绘制
3、模块设计
(二)算法实现与分析
1、哈夫曼树的创建
HfmTree CreateHfmTree(ElemType weight[], char charArr[], int size)
{
PriQueue pQ(size);
HfmTree x, y, z;
for (int i = 0; i < size; i++) {
z.MakeTree(weight[i], charArr[i], x, y);
z.SetWeight(weight[i]);
pQ.Append(z);
z.SetNull();
}
for (int i = 1; i < size; i++) {
pQ.Deal(x);
pQ.Deal(y);
z.MakeTree(x.GetWeight() + y.GetWeight(), '*', x, y); // *区别叶子节点和普通结点
z.SetWeight(x.GetWeight() + y.GetWeight());
pQ.Append(z);
z.SetNull();
}
pQ.Deal(z);
return z;
}
分析:函数传入三个变量,分别是权值数组,要编码的字符数组和字符数量。先依据传入的顺序生成队列。
选择两个权值最小的节点进行结合生成新的二叉树。如果超过两棵树则继续循环。
2、哈夫曼树的编码
void HfmTree::Code(BTNode* t, char a)
{
if (t) {
if (t->ch == a) {
cout << t->num;
}
Code(t->lChild, a);
Code(t->rChild, a);
}
}
分析:传入要编码的字符串,依次将字符串中的字符传入本函数,得到0-1序列
时间复杂度:O(n)
3、哈夫曼树的解码
// 由输入的编码输出相应的字符
void HfmTree::DeCode(BTNode* q)
{
cout << "请输入二进制编码(0和1的组合):" << endl;
string n;
cin >> n;
BTNode* t = q;
int count = n.length();
for (int i = 0; i < count; i++) {
if (n[i] == '0' && t->lChild->ch != '*') {
cout << t->lChild->ch;
t = q;
}
else if (n[i] == '1' && t->rChild->ch != '*') {
cout << t->rChild->ch;
t = q;
}
else if (n[i] == '0' && t->lChild != NULL) {
t = t->lChild;
}
else if (n[i] == '1' && t->rChild != NULL) {
t = t->rChild;
}
else {
cout << "Decode fail!";
return;
}
}
分析:在哈夫曼树的编码数组中查找对应字符的二进制编码并输出。
时间复杂度:O(n)
4、打印哈夫曼树
分析:因为使用先序遍历和中序遍历可以唯一的表示一棵树,所以依次打印哈夫曼树的先序遍历和中序遍历。
时间复杂度:O(n)