目录
实验内容:
删除二叉树的子树:假设二叉树中的结点均不相等,采用二叉链存储,设计递归算法删除根结点值为x的子树。
实验过程:
1.算法设计
设计了一个基于字符输入表达式来创建、打印和删除二叉树节点的功能。主要算法设计过程为:
- 创建二叉树:
1.输入一个字符串,其中包含括号、逗号以及代表节点值的字符。
2.通过遍历字符串,根据字符类型执行相应的操作当遇到'('时,表示进入新的子树,将当前父节点压入栈中并标记即将创建的是左子树;当遇到')'时,表示子树创建完成,弹出栈顶元素;当遇到','时,表示开始创建当前节点的右子树;对于其它字符(即节点值),创建一个新的二叉树节点,并根据当前状态将其链接到相应父节点的左或右子节点。
- 打印二叉树:使用递归方法,从根节点开始,按照先序遍历的方式打印节点值及括号以表示子树结构。
- 删除节点及其子节点:从给定的根节点开始递归地释放所有子节点和根节点的内存。
- 查找并删除指定值节点:定义一个递归函数SearchBiTNode,它在二叉树中查找具有指定值的节点。在查找过程中,当找到目标节点时,调用FreeBiTNode函数删除该节点,并返回true表示删除成功。如果在递归查找过程中没有找到目标节点,则返回false。
主函数流程:创建二叉树,打印创建好的二叉树。输入要删除的节点值,然后进行查找和删除操作。在删除成功的情况下再次打印删除节点后的二叉树。
2.程序清单
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
//定义二叉树节点结构体
typedef struct BiTNode{
char data;
struct BiTNode *lchild, *rchild;
} BiTNode;
//从给定字符串str中创建二叉链表
void CreatBiTNode(BiTNode * &b,char * str)
{
//定义BiTNode指针数组Temp,初始化一个指向BiTNode结构体的指针变量p
BiTNode *Temp[MAXSIZE],*p = NULL;
//栈顶指针,记录当前正在处理的子树的父节点
int top = -1;
int k;
int j=0;
char ch=str[j];
//初始化二叉树为空
b = NULL;
while(ch != '\0')
{
switch(ch)
{
case '(': //遇到(,表示进入新的子树,栈顶指针+1,该节点压入栈中
top++;
Temp[top] = p;
k = 1;//该节点的左子树
break;
case ')'://子树创建成功,栈顶指针-1
top--;
break;
case ',':
k = 2;// 遇到该节点的右子树
break;
default ://如果是节点数据,创建一个新的节点
p = (BiTNode *)malloc(sizeof(BiTNode));
//当前字符为节点的数据
p -> data = ch;
//左右指针为空
p -> lchild = p -> rchild = NULL;
//如果当前树为空,将新创建的节点设为根节点
if(b == NULL)
b = p;
else
{
if(k == 1)
Temp[top] -> lchild = p;//将新节点设置为栈顶元素的左孩子
else if(k == 2)
Temp[top] -> rchild = p;//右孩子
}
}
//移动下一个字符
j++;
ch = str[j];
}
}
//输出二叉树
void PrintBiTNode(BiTNode *b)
{
if(b != NULL)
{
printf("%c",b -> data);//先输出根节点
if(b -> lchild != NULL || b -> rchild != NULL)
{
//有孩子时输出孩子
printf("(");
PrintBiTNode(b -> lchild);//递归输出左孩子
if(b -> rchild != NULL)
{
printf(",");//有右孩子时输出
PrintBiTNode(b -> rchild);//递归输出右孩子
}
printf(")");//孩子输出结束
}
}
}
//删除节点及其子节点
void FreeBiTNode(BiTNode *&b)
{
if(b != NULL)
{
FreeBiTNode(b -> lchild);//递归删除左子树
FreeBiTNode(b -> rchild);//递归删除右子树
free(b);//释放根节点空间
b = NULL;
}
}
//查找节点值为Del的节点
bool SearchBiTNode(BiTNode *&b,char Del)
{
if(b == NULL)
return false;//树为空,找不到该节点,返回false
if(b -> data == Del)
{
FreeBiTNode(b);//找到要删除的节点,调用删除函数将其删除
printf("找到该节点,删除成功!\n");
return true;
}
else if(SearchBiTNode(b -> lchild,Del))
return true;//递归查找其左子树,找到节点,返回true
else if(SearchBiTNode(b -> rchild,Del))
return true;//递归查找其右子树,找到节点,返回true
else
return false;
}
void main()
{
//定义二叉树
BiTNode *b;
//要删除子树的值
char Del;
char str[MAXSIZE];
printf("请输入二叉树:\n");
scanf("%s",&str);
//创建二叉树
CreatBiTNode(b,str);
printf("二叉树创建成功!\n");
//输出二叉树
PrintBiTNode(b);
printf("\n");
printf("请输入要删除节点的值:\n");
//清空缓冲区
fflush(stdin);
scanf("%c",&Del);
if(SearchBiTNode(b,Del)){
//输出删除后的二叉树
PrintBiTNode(b);
}else if(SearchBiTNode(b,Del) == false){
printf("未查找到节点,删除失败!\n");
}
printf("\n");
}
3.复杂度分析
(1)时间复杂度
1.创建二叉树函数(CreatBiTNode 函数):时间复杂度O(n),n为输入字符串的长度。因为需要遍历整个字符串来构建二叉树。
2.打印二叉树函数(PrintBiTNode 函数):时间复杂度O(h),h为二叉树的高度,对于完全二叉树或满二叉树,其高度h接近于节点数n的对数,即h ≈ log_2(n)。
3.删除节点及其子节点函数(FreeBiTNode 函数):时间复杂度 O(n)。在二叉链表中,每个节点最多被访问一次。对于高度为h的二叉链表,其最坏时间复杂度为O(2^h),其中h是树的高度。对于完全二叉树或满二叉树,其高度h接近于节点数n的对数,即h ≈ log_2(n),此时时间复杂度为O(2^(log_2(n))) = O(n)。对于非完全二叉树,实际时间复杂度可能会略小于O(n)。
4.查找并删除节点函数(SearchBiTNode 函数):时间复杂度O(n),同时FreeBiTNode 函数一样。最坏的情况需要遍历整个二叉树。
(2)空间复杂度
1.创建二叉树函数(CreatBiTNode 函数):空间复杂度:代码中使用了一个大小为MAXSIZE的数组Temp作为辅助栈。在最坏情况下(输入字符串表示一个完全二叉树时),栈中最多会存放log_2(n)个节点指针(n为二叉链表的节点数)。但由于MAXSIZE是固定常数,这部分空间消耗可以认为是常数级别的。因此,这段代码的空间复杂度为O(1)
2.打印二叉树函数(PrintBiTNode 函数):空间复杂度:递归调用会占用一定的栈空间,最坏情况下,当二叉树完全不平衡时,递归深度达到 h,因此空间复杂度为 O(h)。
3.删除节点及其子节点函数(FreeBiTNode 函数):空间复杂度:同 PrintBiTNode 函数,递归调用也需要栈空间,最坏情况下的空间复杂度为 O(h)。
4.查找并删除节点函数(SearchBiTNode 函数):空间复杂度:同 PrintBiTNode 和 FreeBiTNode 函数,由于也是采用递归实现,最坏情况下的空间复杂度为 O(h)。