-
树的基本概念:由一个或多个(n>=0)结点组成的有限集合T,有且仅有一个结点称为根(root),当n>1 时,其余结点分为m(m>=0)个互不相交的有限集合T1,T2,…,Tm。每个集合本身又是棵树,被称为这个根的子树。
-
树的结构特点:
1.非线性结构,有一个直接前驱,但可能有多个直接后继(1:n);
2.树的定义具有递归性,即树中有树;
3.树可以为空,即节点个数为0; -
其他概念
1.根->根节点(没有前驱);
2.叶子->终节点(没有后继);
3.森林->指m棵不相交的树的集合;
4.节点的度->一个节点含有的子树个数;
5.树的度->所有节点度的最大值;
6.树的高度深度->树中节点的最大层次;
7.有序树->节点各子树从左至右有序,不能互换(左为第一);
8.无序树->节点各子树可以互换位置;上图中树的节点数=13,树的度=3,树的深度=4;
树的表示方法:
-
顺序存储 :双亲表示法
struct Node{
int data; //节点的值
int parent; //能找到父节点,
}
- 链式存储:孩子表示法
struct ChildNode{
int data; //节点的值
ChildNode* c1,c2,...,cn;//此处是一个链表
}
ChildNode D;
D.ChildNode*链表
- 左子右兄:把普通树转化成二叉树
以上图为例:
1.A的左孩子为B,没有兄弟
2.B的左孩子为E,右兄弟为C
3.E的左孩子为K,右兄弟为F
以此类推得二叉树:
-
定义:n(n>=0)个节点的有限集合,由一个根节点以及两棵互不相交的,分别称为左子树和右子树的二叉树组成;
-
逻辑结构: 一对二(1:2);
-
基本特征:
1.每个节点最多只有两棵子树;
2.左子树和右子树不能颠倒(有序树); -
样子:
-
性质:
1.在二叉树的第i层上至多有2^(i-1)个节点(i>0);
2.深度为k的二叉树至多有2^(k)-1个节点(k>0);
3.对于任何一个二叉树,若度为2的节点数有n2个,则叶子数(n0)必定为n2+1(即n0=n2+1);(n0为度为0的节点) -
结构体:
typedef struct TreeNode {
char val; //该节点表示的值
struct TreeNode* LChild; //左孩子
struct TreeNode* RChild; //右孩子
}Node;
- **满二叉树:**一棵深度为k且有2^k-1个节点的二叉树;
- **完全二叉树:**除了最后一层,其他层上的节点都达到最大值,当最后一层未满时,节点全部靠左侧;
- 具有n个节点的完全二叉树的深度必为[log2^n]+1
- 对完全二叉树,若从上至下,从左至右编号,则编号为i的节点,其左孩子编号必为2i,其右孩子编号必为2i+1;其双亲的编号必为i/2(i=1 时为根除外)
二叉树创建
-
二叉树的创建可以用先序和中序创建
-
通过(中,先)能确定一棵树
-
通过(中,后)能确定一棵树
-
通过(先,后)不能确定一棵树
例:
先序遍历结果:A,D,E,B,C,F
中序遍历结果:D,E,A,C,F,B
可得树为
-
下面重点的#号创建法:
其中#表示NULL
如果先序遍历,结果为:124###3##
//递归的创建
Node* CreateTree()
{
Node* root ; //节点
char ch; //节点的值
cin >> ch; //输入节点的值
if (ch == '#') { //判断节点的值是否为#
root= NULL; //若是则是空节点
}
else {
root = new Node;
root->c = ch; //先序创建 根
root->LChild = CreateTree();// 左
root->RChild = CreateTree();// 右
}
return root;
}
既然我们已经创建出一棵属于自己的二叉树了,那我们就要看看它长什么样子
二叉树的遍历
以此图为例
-
先序遍历 根->左->右
ABCDEFGH -
中序遍历 左->根->右
BDCEAFHG -
后序遍历 左->右->根
DECBHGFA
以先序为例:
//递归遍历
void Show(Node* root)
{
if (root == NULL)
{
return;
}
cout << root->c;// 根
Show(root->LChild);// 左
Show(root->RChild);// 右
}
调换上面代码的顺序就可以达到不同类型的遍历
中序:
void Show(Node* root)
{
if (root == NULL)
{
return;
}
Show(root->LChild); // 左
cout << root->c; // 根
Show(root->RChild);// 右
}
树的非递归遍历
- 树的非递归遍历是通过栈来实现的,这里先不接受
求叶子节点:
上面已经说过叶子节点是:终节点(没有后继);
大家很显然就能看得出这棵树的叶子节点是3
那么我们就**递归判断节点的左右子节点是否为空
**就ok
void GetLeafNode(Node* root,int* count) // count用来计数
{
if (root == NULL)
{
return;
}
if (root->LChild == NULL && root->RChild == NULL)
{
(*count)++;
}
GetLeafNode(root->LChild,count);
GetLeafNode(root->RChild,count);
}
求树的深度:
高度和深度是相反的表示,深度是从上到下数的,而高度是从下往上数。
我们先来看看高度和深度的定义,某节点的深度是指从根节点到该节点的最长简单路径边的条数,而高度是指从该节点到叶子节点的最长简单路径边的条数。
注意:这里边的条数是规定根节点的深度和叶子节点的高度是0;
所以树的深度和高度是相等的,而对其他节点来说深度和高度不一定相等。
很多教材或者书对深度的起点有不同的说法,有的说法是从0,开始,有的是从1开始
这里我们从1开始
可以看出次树的深度和高度为4
int GetDepth(Node* root)
{
if (root == NULL)
{
return -1;
}
return 1 + max(GetDepth(root->LChild), GetDepth(root->RChild));
}
线索二叉树:https://blog.csdn.net/alzzw/article/details/97423394
哈夫曼树:https://blog.csdn.net/alzzw/article/details/97809047
二叉搜索(排序)树;https://blog.csdn.net/alzzw/article/details/97563011
平衡二叉树:https://blog.csdn.net/alzzw/article/details/97613193
B树~B+树:https://blog.csdn.net/alzzw/article/details/97633941
红黑树:https://blog.csdn.net/alzzw/article/details/97770753
到这里有关树的一些基础知识就讲解完了,如果喜欢请收藏关注博主,你的支持是我继续的动力,谢谢了!