文章目录
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为对数)