前言
介绍
🍃数据结构专区:数据结构
参考
该部分知识参考于《数据结构(C语言版 第2版)》116 ~ 122页 及 《数据结构教程》201 ~ 213页
重点
树的基本实现并不难,重点在于对递归的理解才是树这部分知识带来的最大收获,因为树的逻辑结构就保证了使用递归思路来解决是最优的算法
由于树的基础知识太多,这里只进行简单解释,本篇主要是对基本操作代码的解释,后序的文章会跟进树的相关知识和性质的
🌈每一个清晨,都是世界对你说的最温柔的早安:ૢ(≧▽≦)و✨
目录
1、二叉树的基础知识
2、链表树的操作
2.1 宏定义及结构体定义
#include<stdio.h>
#include<iostream>
using namespace std;
typedef char TElemType;
typedef struct BiTNode {
TElemType data;
struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;
2.2 前中后序遍历法
//前序递归遍历法
void PreOrder(BiTree T)
{
if (T != NULL)
{
cout << T->data << " ";
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
//中序递归遍历法
void InOrder(BiTree T)
{
if (T != NULL)
{
InOrder(T->lchild);
cout << T->data << " ";
InOrder(T->rchild);
}
}
//后序递归遍历法
void PostOrder(BiTree T)
{
if (T != NULL)
{
PostOrder(T->lchild);
PostOrder(T->rchild);
cout << T->data << " ";
}
}
2.3 初始化树
//初始化树
void InitTree(BiTree& T)
{
T = NULL;
}
2.4 创建新节点
//创建新节点
BiTNode* CreatNewNode(TElemType value)
{
BiTNode* node = new BiTNode;
//等价于
//BiTNode* node = (BiTNode*)malloc(sizeof(BiTNode));
node->data = value;
node->lchild = NULL;
node->rchild = NULL;
return node;
}
2.5 创建树
//创建树
void CreateTree(BiTree& T, char* definition)
{
static int i = 0; //静态变量,每次递归进入过程中都会i++
char ch = definition[i++];
if (ch == '#')
{
T = NULL;
}
else
{
T = CreatNewNode(ch);
CreateTree(T->lchild, definition);
CreateTree(T->rchild, definition);
}
}
2.6 销毁树
//销毁树
void DestroyTree(BiTree& T)
{
if (T != NULL)
{
DestroyTree(T->lchild);
DestroyTree(T->rchild);
free(T);
T = NULL;
}
}
2.7 判空
//判空
int TreeEmpty(BiTree T)
{
if (T == NULL)
{
return 1;
}
else
{
return 0;
}
}
2.8 求树的深度
//求树的深度
int TreeDepth(BiTree T)
{
//定义左右子树的高度,作为最后返回时的比较值
int lchildh = 0, rchildh = 0;
if (T == NULL)
{
return 0;
}
else
{
lchildh = TreeDepth(T->lchild);
rchildh = TreeDepth(T->rchild);
return lchildh > rchildh ? lchildh + 1 : rchildh + 1;
}
}
2.9 根据值查找节点
//查找某个节点
BiTNode* FindNode(BiTree T, TElemType x)
{
BiTNode* p;//作为遍历
if (T == NULL)
{
return NULL;
}
if (T->data == x)
{
return T;
}
//左递归查找
p = FindNode(T->lchild, x);
if (p != NULL)
{
return p;
}
else
{
//否则进行右递归查找
return FindNode(T->rchild, x);
}
}
2.10 求树根
//求树根
BiTNode* Root(BiTree T)
{
if (T == NULL)
{
printf("ERROR:Tree is NULL!");
}
return T;
}
2.11 求结点总数
//求结点总数
int Nodes(BiTree T)
{
if (T == NULL)
{
return 0;
}
return Nodes(T->lchild) + Nodes(T->rchild) + 1;
}
2.12 输出叶子节点
//输出叶子结点
void DispLeaf(BiTree T)
{
if (T != NULL)
{
if (T->lchild == NULL && T->rchild == NULL)
{
cout << T->data << " "; //访问叶子节点
}
DispLeaf(T->lchild); //输出左子树中的叶子节点
DispLeaf(T->rchild); //输出右子树中的叶子节点
}
}
2.13 计算值为x的节点所在的层数
//计算某个节点值为x的层次(若在根结点 h = 1,树为空h = 0)
int Level(BiTree T, TElemType x, int h)
{
int l;
if (T == NULL)
{
return(0);
}
if (T->data == x)
{
return(h);
}
l = Level(T->lchild, x, h + 1);
if (l != 0)
{
return(l);
}
else
{
return(Level(T->rchild, x, h + 1));
}
}
2.14 计算第k层的节点数
//计算第k层的结点数
void LnodeNum(BiTree T, int h, int k, int& n)
{
if (T == NULL)
{
return;//空树直接返回
}
//处理非空树
if (h == k)
n++; //当前访问的结点在第k层时,n++
else if (h < k) //若当前节点层次小于k,递归处理左右子树
{
LnodeNum(T->lchild, h + 1, k, n);
LnodeNum(T->rchild, h + 1, k, n);
}
}
2.15 复制二叉树
//复制二叉树
void Copy(BiTree T, BiTree& NewT)
{
//复制一棵和T完全相同的二叉树
if (T == NULL)
{
NewT = NULL;
return;
}
else
{
NewT = new BiTNode;
NewT->data = T->data;
Copy(T->lchild, NewT->lchild);
Copy(T->rchild, NewT->rchild);
}
}
2.16 判断两棵树是否相似
//判断两棵树是否相似
bool Like(BiTree T1, BiTree T2)
{
bool like1, like2;
if (T1 == NULL && T2 == NULL)
{
return true;
}
else if (T1 == NULL || T2 == NULL)
{
return false;
}
else
{
like1 = Like(T1->lchild, T2->lchild);
like2 = Like(T1->rchild, T2->rchild);
return(like1 && like2);
}
}
2.17 查找某节点的双亲节点
//查找某节点的双亲节点
//这里需要用到两个函数来完成
//1.辅助函数
BiTNode* ParentHelper(BiTNode* root, BiTNode* cur_e)
{
if (root == NULL || cur_e == NULL)
{
return NULL;
}
//如果root节点的左右节点中某一个是目标节点
if (root->lchild == cur_e || root->rchild == cur_e)
{
return root;
}
//进行左递归查找
BiTNode* leftResult = ParentHelper(root->lchild, cur_e);
if (leftResult != NULL)
{
return leftResult;
}
//否则递归查找右子树
return ParentHelper(root->rchild, cur_e);
}
//2.查询函数
BiTNode* Parent(BiTree& T, BiTNode* cur_e)
{
if (T == NULL || cur_e == NULL)
{
return NULL;
}
//调用辅助函数查找双亲节点
return ParentHelper(T, cur_e);
}
2.18 其他一些不重要函数
//不重要函数
//求某个节点的值
TElemType Value(BiTree& T, BiTNode* cur_e)
{
if (T == NULL || cur_e == NULL)
{
printf("ERROR:Tree or Node is NULL!");
exit(1);
}
return cur_e->data;
}
//给某个节点赋值
void Assign(BiTree& T, BiTNode* cur_e, TElemType value)
{
if (T == NULL || cur_e == NULL)
{
printf("ERROR:Tree or Node is NULL!");
exit(1);
}
cur_e->data = value;
}
//求某节点的左孩子结点
BiTNode* LeftChild(BiTree T, BiTNode* cur_e)
{
if (T == NULL || cur_e == NULL)
{
printf("ERROR: Tree or cur_e is NULL!");
exit(1);
}
return cur_e->lchild;
}
//求某节点的右孩子结点
BiTNode* RightChild(BiTree T, BiTNode* cur_e)
{
if (T == NULL || cur_e == NULL)
{
printf("ERROR: Tree or cur_e if NULL!");
exit(1);
}
return cur_e->rchild;
}
2.19 整体代码(含测试代码)
#include<stdio.h>
#include<iostream>
using namespace std;
typedef char TElemType;
typedef struct BiTNode {
TElemType data;
struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;
//前序递归遍历法
void PreOrder(BiTree T)
{
if (T != NULL)
{
cout << T->data << " ";
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
//中序递归遍历法
void InOrder(BiTree T)
{
if (T != NULL)
{
InOrder(T->lchild);
cout << T->data << " ";
InOrder(T->rchild);
}
}
//后序递归遍历法
void PostOrder(BiTree T)
{
if (T != NULL)
{
PostOrder(T->lchild);
PostOrder(T->rchild);
cout << T->data << " ";
}
}
//初始化树
void InitTree(BiTree& T)
{
T = NULL;
}
//创建新节点
BiTNode* CreatNewNode(TElemType value)
{
BiTNode* node = new BiTNode;
//等价于
//BiTNode* node = (BiTNode*)malloc(sizeof(BiTNode));
node->data = value;
node->lchild = NULL;
node->rchild = NULL;
return node;
}
//创建树
void CreateTree(BiTree& T, char* definition)
{
static int i = 0; //静态变量,每次递归进入过程中都会i++
char ch = definition[i++];
if (ch == '#')
{
T = NULL;
}
else
{
T = CreatNewNode(ch);
CreateTree(T->lchild, definition);
CreateTree(T->rchild, definition);
}
}
//销毁树
void DestroyTree(BiTree& T)
{
if (T != NULL)
{
DestroyTree(T->lchild);
DestroyTree(T->rchild);
free(T);
T = NULL;
}
}
//清空树
//在C代码作为主要函数的代码下,清空树和销毁树是几乎一样的操作
//唯一差别在于,销毁树是树根也销毁,清空树保存其树根
//如果是C++代码下
//BinaryTree类中添加了一个析构函数(~BinaryTree()),它会在对象被删除时自动调用DestroyTree。
//这确保了即使用户忘记显式调用DestroyTree,内存也会被正确释放
//判空
int TreeEmpty(BiTree T)
{
if (T == NULL)
{
return 1;
}
else
{
return 0;
}
}
//求树的深度
int TreeDepth(BiTree T)
{
//定义左右子树的高度,作为最后返回时的比较值
int lchildh = 0, rchildh = 0;
if (T == NULL)
{
return 0;
}
else
{
lchildh = TreeDepth(T->lchild);
rchildh = TreeDepth(T->rchild);
return lchildh > rchildh ? lchildh + 1 : rchildh + 1;
}
}
//查找某个节点
BiTNode* FindNode(BiTree T, TElemType x)
{
BiTNode* p;//作为遍历
if (T == NULL)
{
return NULL;
}
if (T->data == x)
{
return T;
}
//左递归查找
p = FindNode(T->lchild, x);
if (p != NULL)
{
return p;
}
else
{
//否则进行右递归查找
return FindNode(T->rchild, x);
}
}
//求树根
BiTNode* Root(BiTree T)
{
if (T == NULL)
{
printf("ERROR:Tree is NULL!");
}
return T;
}
//求结点总数
int Nodes(BiTree T)
{
if (T == NULL)
{
return 0;
}
return Nodes(T->lchild) + Nodes(T->rchild) + 1;
}
//输出叶子结点
void DispLeaf(BiTree T)
{
if (T != NULL)
{
if (T->lchild == NULL && T->rchild == NULL)
{
cout << T->data << " "; //访问叶子节点
}
DispLeaf(T->lchild); //输出左子树中的叶子节点
DispLeaf(T->rchild); //输出右子树中的叶子节点
}
}
//计算某个节点值为x的层次(若在根结点 h = 1,树为空h = 0)
int Level(BiTree T, TElemType x, int h)
{
int l;
if (T == NULL)
{
return(0);
}
if (T->data == x)
{
return(h);
}
l = Level(T->lchild, x, h + 1);
if (l != 0)
{
return(l);
}
else
{
return(Level(T->rchild, x, h + 1));
}
}
//计算第k层的结点数
void LnodeNum(BiTree T, int h, int k, int& n)
{
if (T == NULL)
{
return;//空树直接返回
}
//处理非空树
if (h == k)
n++; //当前访问的结点在第k层时,n++
else if (h < k) //若当前节点层次小于k,递归处理左右子树
{
LnodeNum(T->lchild, h + 1, k, n);
LnodeNum(T->rchild, h + 1, k, n);
}
}
//复制二叉树
void Copy(BiTree T, BiTree& NewT)
{
//复制一棵和T完全相同的二叉树
if (T == NULL)
{
NewT = NULL;
return;
}
else
{
NewT = new BiTNode;
NewT->data = T->data;
Copy(T->lchild, NewT->lchild);
Copy(T->rchild, NewT->rchild);
}
}
//判断两棵树是否相似
bool Like(BiTree T1, BiTree T2)
{
bool like1, like2;
if (T1 == NULL && T2 == NULL)
{
return true;
}
else if (T1 == NULL || T2 == NULL)
{
return false;
}
else
{
like1 = Like(T1->lchild, T2->lchild);
like2 = Like(T1->rchild, T2->rchild);
return(like1 && like2);
}
}
//查找某节点的双亲节点
//这里需要用到两个函数来完成
//1.辅助函数
BiTNode* ParentHelper(BiTNode* root, BiTNode* cur_e)
{
if (root == NULL || cur_e == NULL)
{
return NULL;
}
//如果root节点的左右节点中某一个是目标节点
if (root->lchild == cur_e || root->rchild == cur_e)
{
return root;
}
//进行左递归查找
BiTNode* leftResult = ParentHelper(root->lchild, cur_e);
if (leftResult != NULL)
{
return leftResult;
}
//否则递归查找右子树
return ParentHelper(root->rchild, cur_e);
}
//2.查询函数
BiTNode* Parent(BiTree& T, BiTNode* cur_e)
{
if (T == NULL || cur_e == NULL)
{
return NULL;
}
//调用辅助函数查找双亲节点
return ParentHelper(T, cur_e);
}
//不重要函数
//求某个节点的值
TElemType Value(BiTree& T, BiTNode* cur_e)
{
if (T == NULL || cur_e == NULL)
{
printf("ERROR:Tree or Node is NULL!");
exit(1);
}
return cur_e->data;
}
//给某个节点赋值
void Assign(BiTree& T, BiTNode* cur_e, TElemType value)
{
if (T == NULL || cur_e == NULL)
{
printf("ERROR:Tree or Node is NULL!");
exit(1);
}
cur_e->data = value;
}
//求某节点的左孩子结点
BiTNode* LeftChild(BiTree T, BiTNode* cur_e)
{
if (T == NULL || cur_e == NULL)
{
printf("ERROR: Tree or cur_e is NULL!");
exit(1);
}
return cur_e->lchild;
}
//求某节点的右孩子结点
BiTNode* RightChild(BiTree T, BiTNode* cur_e)
{
if (T == NULL || cur_e == NULL)
{
printf("ERROR: Tree or cur_e if NULL!");
exit(1);
}
return cur_e->rchild;
}
int main() {
BiTree T, NewT;
char definition[] = "ABD##E##CF##G#H##";
// 测试初始化和创建树
InitTree(T);
CreateTree(T, definition);
cout << "初始化树和创建树的测试:" << endl;
// 测试遍历
cout << "\n前序遍历: ";
PreOrder(T);
cout << "\n中序遍历: ";
InOrder(T);
cout << "\n后序遍历: ";
PostOrder(T);
// 测试TreeEmpty和TreeDepth
cout << "\n\n树是否为空? " << (TreeEmpty(T) ? "Yes" : "No");
cout << "\n树深: " << TreeDepth(T);
// 测试FindNode
TElemType searchValue = 'D';
BiTNode* foundNode = FindNode(T, searchValue);
cout << "\n\n查找节点 '" << searchValue << "': "
<< (foundNode ? "Found" : "Not found");
// 测试Root
BiTNode* root = Root(T);
cout << "\n树根: " << (root ? root->data : ' ');
// 测试Nodes和DispLeaf
cout << "\n所有节点数: " << Nodes(T);
cout << "\n叶子结点: ";
DispLeaf(T);
// 测试Level
cout << "\n\n'E'所在的层数: " << Level(T, 'E', 1);
// 测试LnodeNum
int nodeCount = 0;
LnodeNum(T, 1, 3, nodeCount);
cout << "\n第3层的结点数: " << nodeCount;
// 测试Copy
Copy(T, NewT);
cout << "\n\n复制一棵树,并进行中序遍历: ";
InOrder(NewT);
// 测试Like
cout << "\n上面复制的树和原树是否相似? " << (Like(T, NewT) ? "Yes" : "No");
// 测试Parent
BiTNode* nodeE = FindNode(T, 'E');
BiTNode* parentOfE = Parent(T, nodeE);
cout << "\n\n'E'的双亲节点: " << (parentOfE ? parentOfE->data : ' ');
// 清理内存
DestroyTree(T);
DestroyTree(NewT);
cout << "\n\nAll tests completed." << endl;
return 0;
}
结语
数据结构树这里的相关操作和知识点非常多,并且一环套一环,这里需要大家拥有较多的耐心来一步步走下去,相信一定会更好的!