树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
有一个特殊的结点,称为根结点,根节点没有前驱结点.
除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti(1<= i <= m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继
因此,树是递归定义的。
注意:树形结构中,子树之间不能有交集,否则就不是树形结构
节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为6
叶节点或终端节点:度为0的节点称为叶节点; 如上图:B、C、H、I…等节点为叶节点
非终端节点或分支节点:度不为0的节点; 如上图:D、E、F、G…等节点为分支节点
双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点
孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点
兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点
树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
树的高度或深度:树中节点的最大层次; 如上图:树的高度为4
堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:H、I互为兄弟节点
节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先
子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙
森林:由m(m>0)棵互不相交的树称为森林
树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,既要保存值域,也要保存结点和结点之间
的关系,实际中树有很多种表示方式如:双亲表示法,孩子表示法、孩子双亲表示法以及孩子兄弟表示法
等。我们这里就简单的了解其中最常用的孩子兄弟表示法
一棵二叉树是结点的一个有限集合,可以由根节点,左子树,右子树和空构成
特点:
1.不存在度大于2的结点
2.子树有左右之分,次序不能颠倒,因此二叉树是有序树
- 满二叉树:每一层的节点都满
2.完全二叉树:最下层的节点必须按从左到右的顺序排,满二叉树是一种特殊的完全二叉树
- 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有 2^(i-1)个结点.
- 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2^h-1 .
- 对任何一棵二叉树, 如果度为0其叶结点个数为 n0个, 度为2的分支结点个数为 n2个,则有n0=n2+1。
- 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h是log以2
为底,n+1为真数的对数- 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对
于序号为i的结点有:
1.若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
2.若2i+1=n否则无左孩子
3.若2i+2=n否则无右孩子
由于现在对二叉树结构掌握还不够深入,为了降低学习成本,此处手动快速创建一棵简单的二叉树,快速进入二叉树操作学习,等二叉树结构了解的差不多时,再来研究二叉树真正的创建方式。
typedef int BTDataType;
typedef struct BinaryTreeNode
{
struct BinTreeNode* left; // 指向当前节点左孩子
struct BinTreeNode* right; // 指向当前节点右孩子
BTDataType data; // 当前节点值域
}TreeNode;
TreeNode* BuyTreeNode(int x)
{
TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
assert(node);
node->data = x;
node->left = NULL;
node->right = NULL;
return node;
}
TreeNode* CreateTree()
{
TreeNode* node1 = BuyTreeNode(1);
TreeNode* node2 = BuyTreeNode(2);
TreeNode* node3 = BuyTreeNode(3);
TreeNode* node4 = BuyTreeNode(4);
TreeNode* node5 = BuyTreeNode(5);
TreeNode* node6 = BuyTreeNode(6);
node1->left = node2;
node1->right = node4;
node2->left = node3;
node4->left = node5;
node4->right = node6;
return node1;
}
二叉树的递归遍历结构可以分为前序遍历,中序遍历和后序遍历
访问节点的顺序:根、左子树、右子树
我们用递归去实现前序遍历时要注意返回条件和子问题分治
void PrevOrder(TreeNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
printf("%d ", root->data);
PrevOrder(root->left);
PrevOrder(root->right);
}
这里我们把空节点的值当作N,便于更加清楚前序遍历的逻辑,如果是空节点就打印N并结束当前函数,如果不是空节点就先打印节点的数据,再进入当前节点的左孩子节点,此时进入递归的第二层,如果该节点不为空,就先打印当前节点的值,然后当前节点的左孩子节点,也就是第三层递归。如果递归第二层的节点为空,就返回递归第一层,进入递归第一层节点的右孩子节点判断,一次类推,下面放一张前序遍历的递归图解:
访问节点的顺序:左子树、根、右子树
void InOrder(TreeNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
InOrder(root->left);
printf("%d ",(root->data));
InOrder(root->right);
}
打印结果:
访问节点的顺序:左子树、右子树、根
void OutOrder(TreeNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
OutOrder(root->left);
OutOrder(root->right);
printf("%d ", (root->data));
}
很容易看出,这三种递归遍历结构只是递归的先后顺序有变化,思路如出一辙。
int TreeSize(TreeNode* root)
{
return root==NULL?0:1 + TreeSize(root->left) + TreeSize(root->right);
}
同样利用递归分治,如果根节点是空直接返回0,否则返回左子树的节点数+右子树的节点数+1(根节点的个数)。这里的递归过程是如果有孩子节点就进入孩子节点,进入后就有+1(代表当前的节点),如果还有子节点就继续递归,没有就返回上一级递归,这样就把所有非空节点都过了一遍并完成计数。打印结果:
定义:叶子节点:度为0的节点,就是没有子节点的节点
int TreeLeafSize(TreeNode* root)
{
if (root == NULL)
{
return 0;
}
if (root->left == NULL&&root->right == NULL)
{
return 1;
}
return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}
根据递归分治法,根据叶子节点的特点,我们能知道当当前节点的左右孩子都为空时,当前节点就是叶子节点,于是返回1,如果还不是叶子节点就继续检验左右孩子节点。打印结果:
定义:树中结点的最大层次称为树的深度或高度。(层次:结点的层次从根开始定义起,根为第一层,根的孩子为第二层。树中任一结点的层次等于其双亲结点的层次加1。)
int TreeHeight(TreeNode* root)
{
if (root == NULL)
return 0;
int leftheight = TreeHeight(root->left);
int rightheight = TreeHeight(root->right);
return leftheight > rightheight ? leftheight + 1 : 1 + rightheight;
}
同样先判断根节点为空时高度是否为0,之后比较左子树、右子树的高度,返回高的那个,再+1(根节点)
打印结果:
int TreeKSize(TreeNode* root,int k)
{
assert(k > 0);
if (root == NULL)
return 0;
if (k == 1)
return 1;
if (k > 1)
{
return TreeKSize(root->right, k - 1) + TreeKSize(root->left, k - 1);
}
}
求第k层节点数量,等于求以根节点的左孩子为根的k-1层节点数,加上以根节点的右孩子为根的k-1层节点数。打印第2层节点数的结果结果:
typedef int BTDataType;
typedef struct BinaryTreeNode
{
struct BinTreeNode* left; // 指向当前节点左孩子
struct BinTreeNode* right; // 指向当前节点右孩子
BTDataType data; // 当前节点值域
}TreeNode;
TreeNode* BuyTreeNode(int x)
{
TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
assert(node);
node->data = x;
node->left = NULL;
node->right = NULL;
return node;
}
TreeNode* CreateTree()
{
TreeNode* node1 = BuyTreeNode(1);
TreeNode* node2 = BuyTreeNode(2);
TreeNode* node3 = BuyTreeNode(3);
TreeNode* node4 = BuyTreeNode(4);
TreeNode* node5 = BuyTreeNode(5);
TreeNode* node6 = BuyTreeNode(6);
node1->left = node2;
node1->right = node4;
node2->left = node3;
node4->left = node5;
node4->right = node6;
return node1;
}
void PrevOrder(TreeNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
printf("%d ", root->data);
PrevOrder(root->left);
PrevOrder(root->right);
}
void InOrder(TreeNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
InOrder(root->left);
printf("%d ",(root->data));
InOrder(root->right);
}
void OutOrder(TreeNode* root)
{
if (root == NULL)
{
printf("N ");
return;
}
OutOrder(root->left);
OutOrder(root->right);
printf("%d ", (root->data));
}
int TreeSize(TreeNode* root)
{
return root==NULL?0:1 + TreeSize(root->left) + TreeSize(root->right);
}
int TreeLeafSize(TreeNode* root)
{
/*return (TreeSize(root) + 1) / 2;*/
if (root == NULL)
{
return 0;
}
if (root->left == NULL&&root->right == NULL)
{
return 1;
}
return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}
int TreeHeight(TreeNode* root)
{
if (root == NULL)
return 0;
int leftheight = TreeHeight(root->left);
int rightheight = TreeHeight(root->right);
return leftheight > rightheight ? leftheight + 1 : 1 + rightheight;
/*if (TreeHeight(root->left) > TreeHeight(root->right))
{
return 1 + TreeHeight(root->left);
}
else
return 1 + TreeHeight(root->right);*/
//return root == NULL ? 0 :
// TreeHeight(root->left) > TreeHeight(root->right) ?
// 1 + TreeHeight(root->left) : 1 + TreeHeight(root->right);
}
int TreeKSize(TreeNode* root,int k)
{
assert(k > 0);
if (root == NULL)
return 0;
if (k == 1)
return 1;
if (k > 1)
{
return TreeKSize(root->right, k - 1) + TreeKSize(root->left, k - 1);
}
}
int main()
{
TreeNode* root = CreateTree();
PrevOrder(root);
printf("\n");
InOrder(root);
printf("\n");
OutOrder(root);
printf("\n");
printf("%d ",TreeSize(root));
printf("\n");
printf("%d ", TreeLeafSize(root));
printf("\n%d \n", TreeHeight(root));
printf("%d ", TreeKSize(root, 2));
return 0;
}