目录
二叉树的性质
1和2中规定了根节点的层数是1,注意有的书上或OJ题中会标明根节点的层数,也可能是0.
深度为h的二叉树的节点数区间是 [ 2^(h-1) , 2^h -1]
3、这一点是前人根据经验总结出来的,能很方便解决一些选择题、计算题。
4、上一节讲的堆选数,时间复杂度之所以是O(logN),就是由此得来。
5、在孩子节点不超出数组下标的前提下:左孩子节点下标 = 双亲节点下标*2+1
右孩子节点下标 = 双亲节点下标*2+1。
利用性质可以解决一些相关笔试题。
笔试题(选择)
题一:
利用性质3,很容易得出B。
题二:
A、非完全二叉树肯定不能采用顺序结构,因为它的物理结构不一定是连续的,可能两个数据之间会空很多空间。
C、队列,一般使用链表结构,因为顺序表结构不适合头删。
B,D都可以,单选选A,多选就选A,C。
题三:
这题是第一题的延伸,也是利用性质3.
假设 一棵完全二叉树度为2的节点有N个,则叶子节点有N+1个,度为1的节点设有K个。
2N+K+1 = 2n,可以画一个完全二叉树实验一下,发现度为1的节点要么只有1个要么没有。
所以K = 1 或 K=0 ,带入上式,K = 1时,2N+2 = 2n, N = n-1,叶子节点个数为n
K = 0,N不是整数,排除,所以选A。
前序、中序、后序遍历
用画图的方式我带大家理解一下这三种遍历方式。
前序:(先访问根--->左节点--->右节点)
一棵树访问结束返回或遇NULL返回。
前序节点访问顺序:
1--->2--->3--->NULL--->NULL--->NULL--->4--->5--->NULL--->NULL--->6--->NULL--->NULL
中序:(先访问左节点--->根--->右节点)
同理:
前序节点访问顺序:
NULL--->3--->NULL--->2--->NULL--->1--->NULL--->5--->NULL--->4--->NULL--->6--->NULL
后序:(先访问左节点--->根--->右节点)
同理:
前序节点访问顺序:
NULL--->NULL--->3--->NULL--->2--->NULL--->NULL--->5--->NULL--->NULL--->6--->4--->1
二叉树前中后序遍历代码实现
为了方便,这里就写在一个项目里面,用最简单的方式创建。
创建简易二叉树:
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int BTDataType;
typedef struct BinaryTree
{
BTDataType data;
struct BinaryTree* left;
struct BinaryTree* right;
}BTNode;
BTNode* CreateTree()
{
BTNode* n1 = (BTNode*)malloc(sizeof(BTNode));
assert(n1);
BTNode* n2 = (BTNode*)malloc(sizeof(BTNode));
assert(n2);
BTNode* n3 = (BTNode*)malloc(sizeof(BTNode));
assert(n3);
BTNode* n4 = (BTNode*)malloc(sizeof(BTNode));
assert(n4);
BTNode* n5 = (BTNode*)malloc(sizeof(BTNode));
assert(n5);
BTNode* n6 = (BTNode*)malloc(sizeof(BTNode));
assert(n6);
n1->data = 1;
n2->data = 2;
n3->data = 3;
n4->data = 4;
n5->data = 5;
n6->data = 6;
n1->left = n2;
n1->right = n4;
n2->left = n3;
n2->right = NULL;
n3->left = NULL;
n3->right = NULL;
n4->left = n5;
n4->right = n6;
n5->left = NULL;
n5->right = NULL;
n6->left = NULL;
n6->right = NULL;
return n1;
}
前中后序遍历实现:
void PreOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
printf("%d ", root->data);
PreOrder(root->left);
PreOrder(root->right);
}
void InOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
InOrder(root->left);
printf("%d ", root->data);
InOrder(root->right);
}
void AfterOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
AfterOrder(root->left);
AfterOrder(root->right);
printf("%d ", root->data);
}
int main()
{
BTNode* root = CreateTree();
PreOrder(root);
printf("\n");
InOrder(root);
printf("\n");
AfterOrder(root);
printf("\n");
return 0;
}
代码没什么好说的,看不出什么东西,我们画图来观察调用方式。
以前序为例:
大体调用逻辑如上所示,中序和后序也一样,大家可以自行参考画图。
相关节点计算接口实现
一、计算二叉树的节点个数的接口实现
int TreeSize(BTNode* root)
{
return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}
二、计算叶子节点个数的接口
int TreeLeafSize(BTNode* root)
{
if (root == NULL)
return 0;
if (root->left == NULL && root->right == NULL)
return 1;
return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}
三、计算树的高度的接口
int TreeHight(BTNode* root)
{
if (root == NULL)
return 0;
int lefthight = TreeHight(root->left);
int righthight = TreeHight(root->right);
return lefthight > righthight ? lefthight+1:righthight + 1;
}
计算二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
if (root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
return BinaryTreeLevelKSize(root->left, k - 1) +
BinaryTreeLevelKSize(root->right, k - 1);
二叉树查找值为x的节点 |
先画图分析:这里采用的是前序遍历,先看根是不是要找的数,是就返回节点,不是就找左子树,重复上面步骤,再找右子树。
注意这里代码的关键是在于返回值,如果找到了就保存节点返回上一层,如果左右子树都没找到,注意,一定要记得返回一个NULL,否则上一层就接收不到返回值了。这个NULL与根节点为NULL所返回的NULL不一样,因为它们返回的地方不一样。
代码如下:
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
if (root == NULL)
{
return NULL;
}
if (root->data == x)
return root;
BTNode* leftret = BinaryTreeFind(root->left, x);
if (leftret)
return leftret;
BTNode* rightret = BinaryTreeFind(root->right, x);
if (rightret)
return rightret;
return NULL;
}