0
点赞
收藏
分享

微信扫一扫

数据结构的删除操作

NicoalsNC 2024-11-03 阅读 5
数据结构

前言

介绍

 🍃数据结构专区:数据结构

参考

该部分知识参考于《数据结构(C语言版 第2版)》116 ~ 122页 及 《数据结构教程》201 ~ 213页

重点

树的基本实现并不难,重点在于对递归的理解才是树这部分知识带来的最大收获,因为树的逻辑结构就保证了使用递归思路来解决是最优的算法

由于树的基础知识太多,这里只进行简单解释,本篇主要是对基本操作代码的解释,后序的文章会跟进树的相关知识和性质的

🌈每一个清晨,都是世界对你说的最温柔的早安:ૢ(≧▽≦)و✨


目录

前言

1、二叉树的基础知识

1.1、定义与特点

1.2、基本形态与类型

1.3、性质与存储

1.4、遍历方法

2、链表树的操作

2.1 宏定义及结构体定义

2.2 前中后序遍历法

2.3 初始化树

2.4 创建新节点

2.5 创建树

2.6 销毁树

2.7 判空

2.8 求树的深度

2.9 根据值查找节点

2.10 求树根

2.11 求结点总数

2.12 输出叶子节点

2.13 计算值为x的节点所在的层数

2.14 计算第k层的节点数

2.15 复制二叉树

2.16 判断两棵树是否相似

2.17 查找某节点的双亲节点

2.18 其他一些不重要函数

2.19 整体代码(含测试代码)

结语


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;
}

结语

数据结构树这里的相关操作和知识点非常多,并且一环套一环,这里需要大家拥有较多的耐心来一步步走下去,相信一定会更好的!

举报

相关推荐

0 条评论