二叉树链式结构

1. 二叉树

对于普通的树的增删查改没有用;有用的是由书演变的“搜索二叉树,红黑树,AVL树”
但是学习普通的二叉树可以帮助我们了解树结构的控制(递归)

1.1简单创立一个二叉树
typedef int BTDataType;
typedef struct BinaryTreeNode
{
 BTDataType _data;
 struct BinaryTreeNode* _left;
 struct BinaryTreeNode* _right;
}BTNode;
BTNode* CreatBinaryTree()
{
 BTNode* node1 = BuyNode(1);
 BTNode* node2 = BuyNode(2);
 BTNode* node3 = BuyNode(3);
  BTNode* node4 = BuyNode(4);
 BTNode* node5 = BuyNode(5);
 BTNode* node6 = BuyNode(6);
 
 node1->_left = node2;
 node1->_right = node4;
 node2->_left = node3;
 node4->_left = node5;
 node4->_right = node6;
 return node1;
}

注意:上述代码不是二叉树的正确创建方式,真正的创建方式后续讲解:

1.2树的分类

1.空树
2.非空树
非空树的成员:
根节点;左子树;右子树;

2. 二叉树的遍历

2.1二叉树的遍历的介绍

二叉树的 遍历包括:前序,中序,后序的递归结构遍历;
前序:根,左子树,右子树
中序:左子树;根;右子树
后序:左子树;右子树;根;
层序:一层一层访问
在这里插入图片描述
二叉树的前序遍历


void PrevOrder(BTNode * root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	printf("%d ", root->date);
	PrevOrder(root->left);
	PrevOrder(root->right);

}

二叉树的中序遍历

void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	InOrder(root->left);
	printf("%d ", root->date);
	InOrder(root->right);
}

二叉树的后序遍历

void ProOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	ProOrder(root->left);
	ProOrder(root->right);
	printf("%d ", root->date);

}

二叉树的层序遍历
在这里插入图片描述

void levelOrder(BTNode* root)
{
	//初始化
	Queue q;
	QueueInit(&q);
	if (root)
		QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		printf("%d", front->date);
		QueuePop(&q);
		if (front->left)
		{
			QueuePush(&q, front->left);
		}
		if (front->right)
		{
			QueuePush(&q, front->right);
		}

	}
	QueueDestroy(&q);
}

讲述场景思路:
分而治之
在这里插入图片描述

2.2二叉树遍历的应用
2.2.1二叉树节点个数
int BTreeSize(BTNode* root)
{
	//低配版
	//if (root == NULL)
	//	return 0;
	//return BTreeSize(root->left) + BTreeSize(root->right) + 1;
	//高配版 
	return root==NULL ? 0 : BTreeSize(root->left) + BTreeSize(root->right) + 1;
}
2.2.2二叉树叶子个数
// 求叶子节点的个数
int BTreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}

	if (root->left == NULL
		&& root->right == NULL)
	{
		return 1;
	}

	return BTreeLeafSize(root->left)
		+ BTreeLeafSize(root->right);
}
2.2.3二叉树的高度

抵效方法

int BTreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;
	return BTreeHeight(root->left) > BTreeHeight(root->right)
		? BTreeHeight(root->left) + 1 : BTreeHeight(root->right) + 1;
}

在这里插入图片描述

高效方法:

int BTreeHeight(BTNode* root)
{
	if (root == NULL)
	return 0;
	int rightHeight = BTreeHeight(root->right);
	int leftHeight = BTreeHeight(root->left);
	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
2.2.4二叉树的第k层的元素个数
//二叉树的第k层的元素个数
int BTreeLevelKSize(BTNode* root, int k)
{
	assert(k > 0);
	if (root ==NULL)
		return 0;
	if (k == 1)
	{
		return 1;
	}
	return BTreeLevelKSize(root->left, k - 1)+ BTreeLevelKSize(root->right, k - 1);
}
2.2.4相同树

在这里插入图片描述
这里的树的比较需要从上到下比较:
原因:上方的元素少判断少;时间复杂度低;

bool SameTree(BTNode* p, BTNode* q)
{
	
	if (p == NULL && q == NULL)
	{
		return true;
	}
	if (p == NULL || q == NULL)
	{
		return false;
	}
	if (p->date != q->date)
	{
		return false;
	}
	//将其他情况都排除,只剩下两树元素的对应相等情况
	//所以只需判断下方的子树是否成功
	return SameTree(p->left, q->left) && SameTree(p->right, q->right);

}
2.2.5 二叉树查找值为x的结点
//二叉树查找值为x的结点
BTNode* BTreeFind(BTNode*root,BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->date == x)
	{
		return root;
	}
	BTNode* ret1 = BTreeFind(root->left, x);
	if (ret1)
		return ret1;
	BTNode* ret2 = BTreeFind(root->right, x);
	if (ret2)
		return ret2;
	return NULL;//找不到的时刻
}

注意:找不到的情况;
递归图
在这里插入图片描述

2.2.6单值二叉树

图示化:
在这里插入图片描述

//单值二叉树
bool isUnivalTree(BTNode * root)
{
	if (root == NULL)
		return true;
	if (root->left->date != root->date)
		return false;
	if (root->right->date != root->date)
		return false;
	return isUnivalTree(root->left) && isUnivalTree(root->right);

}
2.2.7对称树

在这里插入图片描述

bool _isSymmetric(BTNode* leftRoot, BTNode* rightRoot)
{
	if (leftRoot == NULL && rightRoot == NULL)
	{
		return true;
	}
	if (leftRoot == NULL || rightRoot == NULL)
	{
		return false;
	}
	if (leftRoot->date != rightRoot->date)
		return false;
	return _isSymmetric(leftRoot->left, rightRoot->right)
		&& _isSymmetric(leftRoot->right, rightRoot->left);
}
bool isSymmetric(BTNode* root)
{
	return _isSymmetric(root->left, root->right);
}
2.2.7 前序排列链表
int BTreeSize(BTNode* root)
{
	//低配版
	//if (root == NULL)
	//	return 0;
	//return BTreeSize(root->left) + BTreeSize(root->right) + 1;
	//高配版 
	return root==NULL ? 0 : BTreeSize(root->left) + BTreeSize(root->right) + 1;
}
void _preorder(BTNode* root, int* a, int i)
{
	if (root == NULL)
	{
		return;
	}
	a[i++] = root->date;
	_preorder(root->left, a, i);
	_preorder(root->right, a, i);

}
int* preorderTraversal(BTNode* root, int* returnSize)//后边那个指针是元素个数的指针;
{
	*returnSize = BTreeSize(root);
	int* a = (int*)malloc(*returnSize * sizeof(int));
	int i = 0;
	_preorder(root, a, i);
	return a;
}

在这里插入图片描述
改进版:(直解将下标地址传过去)

//将二叉树前序输入到链表中
void _preorder(BTNode* root, int* a, int * pi)
{
	if (root == NULL)
	{
		return;
	}
	a[*pi++] = root->date;
	_preorder(root->left, a, pi);
	_preorder(root->right, a, pi);

}
int* preorderTraversal(BTNode* root, int* returnSize)//后边那个指针是元素个数的指针;
{
	*returnSize = BTreeSize(root);
	int* a = (int*)malloc(*returnSize * sizeof(int));
	int i = 0;
	_preorder(root, a, &i);
	return a;
}

这里不要使用全局变量:
原因:OJ题会多次调用,使全局变量每次的数据都有残留;
在这里插入图片描述

2.2.8另一棵树的子树

正确示例:
在这里插入图片描述
错误示例:
在这里插入图片描述

bool SameTree(BTNode* p, BTNode* q)
{
	
	if (p == NULL && q == NULL)
	{
		return true;
	}
	if (p == NULL || q == NULL)
	{
		return false;
	}
	if (p->date != q->date)
	{
		return false;
	}
	//将其他情况都排除,只剩下两树元素的对应相等情况
	//所以只需判断下方的子树是否成功
	return SameTree(p->left, q->left) && SameTree(p->right, q->right);

}
bool isSubtree(BTNode* root, struct TreeNode* subRoot)
{
	if (root == NULL)
		return false;
	if (SameTree(root, subRoot))
		return true;
	return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}
2.2.9二叉树的销毁

图解
在这里插入图片描述

对于二叉树的销毁,使用的顺序是后续;原因:左右子树的销毁都需要根的帮助;

//二叉树的销毁
void  BTreeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	BTreeDestory(root->left);
	BTreeDestory(root->right);
	free(root);
}
2.2.10二叉树的创建
//创建二叉树
BTNode* CreateTree(char* a, int* pi)
{
	if (a[*pi] == "#")
	{
		(*pi)++;
		return NULL;
	}
	BTNode* root = BuyNode(a[*pi]);
	(*pi)++;
	root->left = CreateTree(a, pi);
	root->right = CreateTree(a, pi);
	return root;
}

在这里插入图片描述

2.2.11判断是否为完全二叉树

完全二叉树的特点:连续,最后一层为1到满,中间没有间隔
在这里插入图片描述
这里使用队列插入判断,如果队列成上方那样的效果就不是完全二叉树,如果如下方那样就是完全二叉树;
在这里插入图片描述

//判断二叉树是否是完全二叉树
bool BTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)
		QueuePush(&q, root);
	while (!QueueEmpty(&q))
    {
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		//遇到空就跳出
		if (front == NULL)
		{
			break;
		}
		QueuePush(&q, front->left);
		QueuePush(&q, front->right);
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		if (front)
		{
			QueueDestroy(&q);
			return false;
		}
	}
	QueueDestroy(&q);
	return true;
}

前中后序的作用
前序确定根
中序确定左右区间
后序确定根
在这里插入图片描述

3.二叉树的性质

1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有 个结点.
2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是 .2^h-1;

在这里插入图片描述

3. 对任何一棵二叉树, 如果度为0其叶结点个数为n0 , 度为2的分支结点个数为n2 ,则有 n2= n0+1

解析
n1加 n0和n2不增加也不减少
n2加 n0加1,n1减1

4.度为1的接结点要么是1要么是0;

5.若规定根节点的层数为1,具有n个结点的满二叉树的深度,h= .log2(n+1) (ps:log2(n+1)是log以2为底,n+1为对数)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值