二叉树基础操作

一、二叉树数的概念

1,概念

二叉树:一棵二叉树是结点的一个有限集合,该集合: 1. 或者为空 2. 由一个根节点加上两棵别称为左子树和右子树的二叉树组成

如图所示:

注意:二叉树不存在度为3结点,它的子树有左右之分,次序不能跌倒,因此二叉树是有序数

 

特殊二叉数:

满二叉树:一个二叉树,如果其每一层的结点都达到最大值,即结点个数为2^k-1,k为二叉树层数,则该树为满二叉树。

 

完全二叉树:完全二叉树是由满二叉树引出,该树的最后一层结点没有达到最大值,其他层数结点都到达最大值,称为完全二叉树。

 二、二叉树的性质

1. 若规定根节点的层数为1,则一棵非空二叉树的 第i层上最多有 2^(i-1) 个结点.
2. 若规定根节点的层数为1,则 深度为h的二叉树的最大结点数是2^h-1
.
3. 对任何一棵二叉树, 如果度为0其叶结点个数为 , 度为2的分支结点个数为 ,则有 n0=n2+1
(n0为度为0的结点,n2为度为2的结点)
4. 若规定根节点的层数为1,具有 n个结点的满二叉树的深度,h=log2(n+1)
. (ps: log2(n+1)是log以2 为底,n+1为对数)
5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于子序号为i的结点,有:
若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

 

三、二叉树基本操作

1.二叉树结构

二叉树包括:根结点,左孩子,右孩子

typedef int DataType;

typedef struct Tree
{
	DataType data;           //定义结点值
	struct Tree* left;       //定义左孩子
	struct Tree* right;      //定义右孩子
}Tree;

2.二叉树创建

Tree*CreateTree()
{
	Tree*T;
	DataType x;
	//输入结点的值
	cin >> x;
	//该节点为0,说明结点为空
	if (x == 0)
	{
		T = NULL;
	}
	else
	{
		//为结点创建空间
		T = (Tree*)malloc(sizeof(Tree));
		if (T == NULL)
		{
			printf("空间申请失败!!!\n");
			return NULL;
		}
		//为结点赋值
		T->data = x;
		//递归创建左右子树
		T->left = CreateTree();
		T->right = CreateTree();
	}
	return T;
}

3.二叉树遍历

(1)前序遍历

特点:先访问根结点,再遍历左子树,最后遍历右子树

void PreBinaryTree(Tree*T)
{
	if (T == NULL)
	{
		return;
	}
	cout << T->data << " ";
	PreBinaryTree(T->left);
	PreBinaryTree(T->right);
}

(2)中序遍历

特点:先遍历左子树,再访问根结点,最后遍历右子树

void InOrderTree(Tree* T)
{
	if (T == NULL)
	{
		return;
	}
	InOrderTree(T->left);
	cout << T->data << " ";
	InOrderTree(T->right);
}

(3)后序遍历

特点:先遍历左子树再遍历右子树,最后访问根结点

void InOrderTree(Tree* T)
{
	if (T == NULL)
	{
		return;
	}
	InOrderTree(T->left);
	cout << T->data << " ";
	InOrderTree(T->right);
}

(4)层序遍历

层序遍历相对于前三种遍历,需要用队列进行辅助操作,具体操作:定义一个队列,首先将二叉树的第一个结点入队,while循环判断该队列是否为空,不为空的话,则先进行出队,然后判断该树的左又子树是否为空,不为空则入队。

void LevelTree(Tree*T)
{
	//定义一个队列
	queue<Tree*>q;
	Tree*t=T;
	//将二叉树第一个结点入队
	q.push(t);
	while (!q.empty())
	{
		//将t指向队头元素
		t = q.front();
		//输出队头元素,出队
		cout << t->data << " ";
		q.pop();
		//将左右孩子入队
		if (t->left!=NULL)
		{
			q.push(t->left);
		}
		if (t->right!=NULL)
		{
			q.push(t->right);
		}
	}
}

4.二叉树结点个数

int BinaryTreeSize(Tree* T)
{
	//如果树为空,返回0
	if (T == NULL)
	{
		return 0;
	}
	//如果左子树和右子树都为空,说明该结点为叶子结点,返回1
	if (T->left == NULL && T->right == NULL)
	{
		return 1;
	}
	//树的结点等于 左子树的结点 + 右子树的结点 + 根结点(1)
	return 1 + BinaryTreeSize(T->left) + BinaryTreeSize(T->right);
}

5.二叉树叶子结点

int BinaryTreeLeafSize(Tree* T)
{
	if (T == NULL)
	{
		return 0;
	}
	//左子树为空且右子树为空,说明该结点为叶子结点,返回1
	if (T->left == NULL && T->right == NULL)
	{
		return 1;
	}
	//树的叶子结点个数等于 左子树的叶子结点 + 右子树的叶子结点
	return BinaryTreeLeafSize(T->left) + BinaryTreeLeafSize(T->right);
}

6.二叉树第k层结点个数

int BinaryTreeLevelKSize(Tree* T, int k)
{
	//树为空或者k的值小于1时,不存在,返回0
	if (T == NULL || k < 1)
	{
		return 0;
	}
	//层数为1时,返回1
	if (k == 1)
	{
		return 1;
	}
	//第k层结点个数等于 左子树的第k-1层结点个数 + 右子树的第k-1层结点个数
	return BinaryTreeLevelKSize(T->left,k-1) + BinaryTreeLevelKSize(T->right,k - 1);
}

7.二叉树的高度

int max(int a, int b)
{
	return a > b ? a : b;
}
//二叉树的高度
int BinaryTreeHeight(Tree* T)
{
	//树为空,返回0
	if (T == NULL)
	{
		return 0;
	}
	//树的高度等于 左子树的高度和右子树高度的最大值 + 1
	return 1 + max(BinaryTreeHeight(T->left), BinaryTreeHeight(T->right));
}

8.二叉树寻找结点

Tree* BinaryTreeFind(Tree*T,DataType x)
{
	if (T == NULL)
	{
		return NULL;
	}
	//寻找到,返回
	if (T->data == x)
	{
		return T;
	}
	//查找左子树,如果左子树中有与之相同是结点,则返回,否则查找右子树
	Tree*t=BinaryTreeFind(T->left, x);
	if (t != NULL)
	{
		return t;
	}
	return BinaryTreeFind(T->right, x);
}

9.二叉树的销毁

销毁的时候需传递二级指针,因为需要改变指针的指向,要传递指针的地址

在销毁时,不能先销毁根结点,因为其左子树和右子树是通过根结点访问的,如果根结点先被销毁,则其左子树和右子树在后序程序中无法被访问,会出现错误。

void BinaryTreeDestory(Tree** T)
{
	if (*T == NULL)
	{
		return;
	}
	BinaryTreeDestory(&(*T)->left);
	BinaryTreeDestory(&(*T)->right);
	free(*T);
	*T == NULL;
}

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值