树的基本概念和性质及其操作

树的基本概念和性质及其操作

结点:树的数据元素
***结点的度:有几个直接后继就是几度,亦称次数

结点的层次:
中断结点:从根到该结点的层数(根结点算第一层)
分支结点:度为0的结点,即叶子结点

***树的度:所有结点度中的最大值
***树的深度:所有结点中最大的层数

由于树中,每个根结点的后继结点不确定,对于结点的存储关系难以确定,导致直接研究树
是一个很难得问题,问题解决得办法在于,所有的树都可以转换成二叉树,二叉树在所有的树中是
最简单的,他的存储和恢复也相对比较简单,所以我们直接转为研究二叉树;
二叉树的基本性质
1:在二叉树的第i层上,最多有2exp(i-1)个结点;
2:深度为k的二叉树至多有2exp(k)-1个结点;(等比数列求和)
3:如果不是完全二叉树,则一律转为完全二叉树!方法很简单,将各层空缺统统补上虚结点,其内容为空。

树的遍历规则:
1.二叉树由根,左子树,右子树构成,定义为D,L,R
2.D,L,R的自由排列组合定义了六种可能的遍历方案(A(3,3)),LDR,LRD,RLD,RDL,DLR,DRL
3.如果限定先左后右,则有三种实现方案:DLR 先(根)序遍历,LDR中(根)序遍历,LRD后(根)序遍历;
注:“先,中,后”的意思是指访问的结点D是先于子树出现还是后于子树出现;
先序遍历: 根 ,左子树,右子树;
中序遍历:左子树,根,右子树;
后序遍历:左子树,右子树,根;
先序遍历不能确定一棵树,中序和后续可以确定树;

树的表示法:(1)二叉链法:包括一个数据域,一个左指针域,一个右指针域;然后把他们串起来;
(2)三叉链表示法:每个结点包含一个数据域,一个左指针域,一个右指针域,再加一个指向双亲结点的指针域;
在这里插入图片描述
由于树本身就是递归定义的,所以,对所有关于树的API函数,递归是一个很好的思想。我练习了树的三种遍历方式,求树的叶子结点的个数,树的深度,树的拷贝等几个API函数

#include<iostream>
using namespace std;
typedef struct BitNode
{
	int data;
	struct BitNode* lchild, * rchild;
}BitNode;
typedef struct BiNode* Bitree;
void preorder(BitNode* T)
{
	if (T == NULL)
	{
		return;
	 }
	cout << T->data<<" ";
	if (T->lchild != NULL)
	{
		preorder(T->lchild);
	}
	if (T->rchild != NULL)
	{
		preorder(T->rchild);

	}
	return;
}
void midorder(BitNode* T)//传来的是树的根节点
{
	if (T == NULL)
	{
		return;
	}

	if (T->lchild != NULL)//先遍历树的左子树
	{
		midorder(T->lchild);
	}
	cout << T->data << " ";
	if (T->rchild != NULL)//再遍历树的根结点
	{
		midorder(T->rchild);

	}
	return;
}
void postorder(BitNode* T)//传来的是树的根节点
{
	if (T == NULL)
	{
		return;
	}

	if (T->lchild != NULL)//先遍历树的左子树
	{
		postorder(T->lchild);
	}
	
	if (T->rchild != NULL)//再遍历树的右子树
	{
		postorder(T->rchild);

	}
	cout << T->data << " ";//最后遍历树的根节点
	return;
}

/* 写法1:定义全局变量
int sum = 0;//全局变量用于统计叶子结点的个数
void CountLeafNum(BitNode* node)
{
	if(node==NULL)
	{
		return ;
	}
	if (node->lchild==NULL && node->rchild==NULL)//求根节点的叶子结点的个数
	{
		sum++;
	}
	CountLeafNum(node->lchild);//求左子树的叶子结点的个数
	CountLeafNum(node->rchild);//求右子树的叶子结点的个数
}*/
// 写法2:指针做函数参数
void CountLeafNum2(BitNode* node,int* sum)
{
	if (node == NULL)
	{
		return;
	}
	if (node->lchild == NULL && node->rchild == NULL)//求根节点的叶子结点的个数
	{
		*sum = *sum + 1;
		//或者这么写
		//(*sum)++;但是不能这么写:*sum++ 因为++的优先级高,指针指向了别的地方

	}//写在这里相当于先序遍历
	CountLeafNum2(node->lchild,sum);//求左子树的叶子结点的个数
	/*if (node->lchild == NULL && node->rchild == NULL)//求根节点的叶子结点的个数
	{
		*sum = *sum + 1;
		//或者这么写
		//(*sum)++;但是不能这么写:*sum++ 因为++的优先级高,指针指向了别的地方

	}写在这里相当于中序遍历*/
	CountLeafNum2(node->rchild,sum);//求右子树的叶子结点的个数
	/*if (node->lchild == NULL && node->rchild == NULL)//求根节点的叶子结点的个数
	{
		*sum = *sum + 1;
		//或者这么写
		//(*sum)++;但是不能这么写:*sum++ 因为++的优先级高,指针指向了别的地方

	}写在这里相当于后序遍历*/

}
//求树的高度
int depth(BitNode* node)
{
	int depthvalue = 0;
	int depthLeftValue = 0, depthRightValue = 0;
	if (node == NULL)
	{
		return 0;//递归结束的条件
	}
	depthLeftValue = depth(node->lchild);
	depthRightValue = depth(node->rchild);
	depthvalue = 1 + ((depthLeftValue > depthRightValue) ? depthLeftValue : depthRightValue);
	return depthvalue;	
}
BitNode* copy(BitNode* T)
{
	//拷贝二叉树的思想是,首先拷贝结点的数据然后拷贝结点的关系
	BitNode* newLptr = NULL;
	BitNode* newRptr = NULL;
	BitNode* node = NULL;
	if (T == NULL)
	{
		return NULL;
	}
	newLptr = copy(T->lchild);//在递归内部拷贝左子树的根结点和结点之间的关系
	newRptr = copy(T->rchild);//同上,拷贝右子树

	node = (BitNode*)malloc(sizeof(BitNode));
	if (node == NULL)
	{
		return NULL;
	}
	node->data = T->data;//根结点的拷贝
	node->lchild = newLptr;//根结点左子树的拷贝
	node->rchild = newRptr;//根结点右子树的拷贝
	return node;
}
void main()
{
	BitNode nodeA, nodeB, nodeC, nodeD, nodeE;
	memset(&(nodeA), 0, sizeof(BitNode));
	memset(&(nodeB), 0, sizeof(BitNode));
	memset(&(nodeC), 0, sizeof(BitNode));
	memset(&(nodeD), 0, sizeof(BitNode));
	memset(&(nodeE), 0, sizeof(BitNode));
	nodeA.data = 1;
	nodeB.data = 2;
	nodeC.data = 3;
	nodeD.data = 4;
	nodeE.data = 5;
	nodeA.lchild = &nodeB;
	nodeA.rchild = &nodeC;
	nodeB.lchild = &nodeD;
	nodeC.lchild = &nodeE;
	BitNode *newnode=NULL;
	newnode = copy(&nodeA);
	cout << "先序遍历拷贝树: ";
	preorder(newnode);
	int mysum = 0;
	CountLeafNum2(&nodeA,&mysum);
	cout << "叶子结点的个数: " << mysum<<endl;
	cout << "树的深度: " << depth(&nodeA) << endl;
	cout << "先序遍历树: ";
	preorder(&nodeA);	
	cout << "\n中序遍历树: ";
	midorder(&nodeA);
	cout << "\n后序遍历树: ";
	postorder(&nodeA);
	return;
}

运行结果:在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值