1.实验任务说明:说明1:以下二叉树均以二叉链表作为存储结构。
说明2:为使实验程序标准化、且简洁直观,给出二叉树的结点结构。
//二叉链表的结构
typedef char datatype;
typedef struct BiNode
{
datatype data;
struct BiNode *lchild, *rchild;
}bitree;
说明3:完成实验任务的同学请将实验报告以及源码文件以附件形式提交到MOOC平台上,实验报告命名为:实验报告六.doc 源码程序命名为:test6.c,拓展项目保存为huffmancode.c
编程要求:
(1)输入和输出都要有说明性语句提示;
例如:printf(“请输入结点个数:”);
Scanf(“%d”,&len);
(2)代码整齐,一句一行,变量命名尽量见名之意
2.实验内容及要求:
在上一次实验的基础上,(已经创建好二叉树,并且进行了前中后序遍历),完成本次实验。
基础实验项目:
1.以递归方式计算二叉树深度,函数名Depth(bitree *root);
2.以递归方式计算结点总数,函数名Count(bitree *root);
3. 以递归方式计算叶子结点总数,函数名leafNum(bitree *root);
4. 以递归方式删除整颗二叉树,函数名deleteTree()。
拓展实验项目:
创建哈夫曼树并输出。
#include <stdio.h>
#include <stdlib.h>
#define Maxsize 20
//二叉链表的结构
typedef char datatype;
typedef struct BiNode
{
datatype data;
struct BiNode* lchild, * rchild;
}bitree;
//非递归前序遍历所需要使用的栈----使用链栈最佳,无需考虑栈溢出这种情况
typedef struct Stack {
//元素设置为树的结点
bitree* Node;
struct Stack* next;
}PreStack;
//前序遍历的递归算法
void PreOrder(bitree* root);
//中序遍历的递归算法
void InOrder(bitree* root);
//后序遍历的递归算法
void PostOrder(bitree* root);
//前序遍历的非递归算法
void PreOrder1(bitree* root);
//创建空链栈
PreStack* InitLinkStack();
//入栈
void PushElem(PreStack* head, bitree* Node);
//出栈---设置为直接输出出栈元素
void PopElem(PreStack* head, bitree** Node);
//以递归方式创建二叉树
bitree* creatBitree();
//删除二叉树
void deleteTree(bitree* root);
//计算二叉树的深度
int Depth(bitree* root);
//计算结点总数
int Count(bitree* root); //n为结点总数
//计算叶子结点总数
int leafNum(bitree* root);
//***选做***以广义表的形式输出二叉树结构
void displayBitree(bitree* root);
int main(int argc, char* argv[])
{
bitree* root = NULL;
int depthOfTree = 0;
int n = 0, n0 = 0, x = 0;
printf("创建二叉树,请输入二叉树中的结点值(字符):\n");
root = creatBitree();
printf("\n二叉树的前序遍历序列为 : ");
if (root != NULL) PreOrder(root);
printf("\n二叉树的中序遍历序列为 : ");
if (root != NULL) InOrder(root);
printf("\n二叉树的后序遍历序列为 : ");
if (root != NULL) PostOrder(root);
printf("\n二叉树的前序序列(非递归): ");
if (root != NULL) PreOrder1(root);
//以广义表的形式输出二叉树结构
printf("\n以广义表的形式输出二叉树结构:\n ");
displayBitree(root);
depthOfTree = Depth(root);
printf("\n二叉树的高度为:%d\n ", depthOfTree);
n = Count(root);
printf("\n二叉树的结点总数为:%d\n ", n);
n0 = leafNum(root);
printf("\n二叉树的叶子结点总数为:%d\n ", n0);
deleteTree(root);
printf("\n二叉树已被删除,谢谢使用!\n ");
return 0;
}
//以递归方式创建二叉树
bitree* creatBitree()
{
char ch = 'a';
printf("请输入:");
scanf_s("%c", &ch, sizeof(char));
getchar();//清空输入的缓存区域----scanf会吸收回车键,如果不加入,则导致无限递归,造成程序的栈溢出
if (ch == '#') {
return NULL;
}
else {
bitree* boot = (bitree*)malloc(sizeof(bitree));
if (!boot)exit(-1);
boot->data = ch;
boot->lchild = creatBitree();
boot->rchild = creatBitree();
return boot;
}
}
/*在哪个位置输出, 就属于什么遍历类型*/
//前序遍历的递归算法
void PreOrder(bitree* root)
{
if (root == NULL)
return;
else {
printf("%c", root->data);
PreOrder(root->lchild);
PreOrder(root->rchild);
}
}
//中序遍历的递归算法
void InOrder(bitree* root)
{
if (root == NULL)
return;
else {
PreOrder(root->lchild);
printf("%c", root->data);
PreOrder(root->rchild);
}
}
//后序遍历的递归算法
void PostOrder(bitree* root)
{
if (root == NULL)
return;
else {
PreOrder(root->lchild);
PreOrder(root->rchild);
printf("%c", root->data);
}
}
//前序遍历的非递归算法---每扫描一个结点,将其输出并压入栈;左子树为空,则出栈扫描右子树(分治、dp)
void PreOrder1(bitree* root)
{
//存放数据的栈的头结点
PreStack* head = InitLinkStack();
//p为指向当前结点的指针或扫描指针
bitree* p = root;
while (p || head->next != NULL)
{
while (p)
{
printf("%c", p->data);
PushElem(head, p);
p = p->lchild;
}
if (head->next != NULL)
{
PopElem(head, &p);
p = p->rchild;
}
}
}
//创建空链栈
PreStack* InitLinkStack()
{
PreStack* head = (PreStack*)malloc(sizeof(PreStack));
if (!head)exit(-1);
head->next = NULL;
}
//入栈
void PushElem(PreStack* head, bitree* Node)
{
PreStack* t = (PreStack*)malloc(sizeof(PreStack));
if (!t)exit(-1);
t->Node = Node;
t->next = head->next;
head->next = t;
}
//出栈---设置为直接输出出栈元素
void PopElem(PreStack* head, bitree** Node)
{
if (head->next == NULL)
return;
PreStack* t = head->next;
*Node = t->Node;
head->next = t->next;
free(t);
}
//删除二叉树
void deleteTree(bitree* root)
{
if (root)
{
//递归删除二叉树------自下而上、先叶后父,分治思想
deleteTree(root->lchild);
deleteTree(root->rchild);
free(root);
}
}
//计算结点总数
int Count(bitree* root)
{
if (!root)
return 0;
//尾递归,一直搜索到叶子结点然后回溯,+1是因为扫到了叶子结点,属于叶子个数
return Count(root->rchild) + Count(root->lchild) + 1;
}
//计算叶子结点总数
int leafNum(bitree* root)
{
//想了好久,还是没找到错误的地方,不建议参考;
if (root == NULL)return 0;
else {
if (root->rchild == NULL && root->lchild == NULL)
return 1;
return Count(root->lchild) + Count(root->rchild);
}
}
//计算二叉树的深度
int Depth(bitree* root)
{
if (root == NULL)
return 0;
else
{
//兵分两路进行深度搜索,每搜索一次,高度加一;遇到分叉,返回高度最大的那个分支
int lDepth = Depth(root->lchild);
int rDepth = Depth(root->rchild);
return lDepth > rDepth ? lDepth + 1 : rDepth + 1;
}
}
//***选做***以广义表的形式输出二叉树结构
//按照二叉树在广义表的表达形式:a(b,c)属于一个结点;a(b(c,d),e(f,g))是一个高度为三的慢二叉
void displayBitree(bitree* root)
{
//先输出父节点
printf("%c", root->data);
if (root->lchild)
{
//若左子树不为空,先将左括号‘(’输出,然后递归搜索左子树,如果右子树为空,则输出右括号')'
printf("(");
displayBitree(root->lchild);
if (!root->rchild)
printf(")");
}
if (root->rchild)
{
//若左子树为空,则输出左括号‘(’,主要是考虑了左子树为空,无法输出左括号的情形
if (!root->lchild)
printf("(");
//输出左右子树的辨识标志‘,’---a(,b(c,d))---一个左子树为空的二叉树的广义表表示
printf(",");
//递归搜索右子树
displayBitree(root->rchild);
//进行括号匹配
printf(")");
}
}