1.树的概念
树(tree)是一种数据结构,不同于线性数据结构,它属于树形数据结构,如同它的名字一样,它就和现实中的树类似,例如:
这棵树拥有14个节点,共4层,为一棵三叉树;
他很像现实中的树倒转过来一样,顶层为根,中间为树枝,地下为叶子,分别称为根节点,中间节点,叶子节点;
树结点的概念
一个节点有以下几个概念:
(1).父节点
一个节点(除了根节点)的父节点就是它上面一层的与它直接相连的节点,一个节点有且仅有一个父节点;
(2).子节点
一个节点(除了叶子节点)的子节点就是它下面一层的与它直接相连的节点,一个节点可能有多个子结点,也有可能没有子节点(叶子节点);
(3).根节点
根节点是唯一的一个没有父节点的节点,他是一棵树组成的基本,任何非空树的树都必须有根节点(空树没有节点);
(4).叶子节点
叶子节点可以有任意多个,它们没有子节点,是一棵树组成的基本,特别的,只有一个节点的树的根节点也是叶子节点;
2.二叉树的概念
(1).二叉树的构造
二叉树(binary_tree),这种树每个节点最多只有两个分叉,它是许多高级数据结构的基础,例如线段树,平衡树,树套树等等,是数据结构重要的一环;
二叉树其实就相当于一个树状的链表,可以这样构造:
struct node{
int value;
node *father, *left_son, *right_son;
};
不难发现,这与链表有异曲同工之妙,只是将一对一变成了一对多而已;
(2).完全二叉树
完全二叉树就是一种可以用数组存储的二叉树,它的叶子节点都在最后两行,最后一行的叶子节点在倒数第二行的左边;
例如:
它可以这样存储:
int tree[Max_tree_number]; // 树
tree[this_node] // 当前节点
tree[this_node << 1] // 左子节点
tree[(this_node << 1) + 1] // 右子节点
(3).满二叉树
满二叉树是特殊的完全二叉树,它的叶子节点都在最后一层,它的节点正好是个,它也是一棵平衡二叉树;
3.二叉树的遍历
二叉树的遍历有四种,分别是先序遍历,中序遍历,后序遍历与层序遍历;
注:前三种遍历方式的代码十分相似,只是在递归代码中输出的位置不同:
void dfs(int node){
// 先序遍历
dfs(node << 1);
// 中序遍历
dfs((node << 1) + 1);
// 后序遍历
}
(1).先序遍历
先序遍历遵守根左右的规则,例如:
这棵树的先序遍历为:
1,2,4,8,9,5,10,11,3,6,7
(2).中序遍历
中序遍历遵守左根右的规则,例如上图:
这棵树的中序遍历为:
8,4,9,2,10,5,11,1,6,3,7
(3).后序遍历
后序遍历遵守左右根的规则,例如上图:
这棵树的后序遍历为:
8,9,4,10,11,5,2,6,7,3,1
(4).层序遍历
层序遍历遵守广度优先搜索(BFS)的规则,例如上图:
这棵树的层序遍历为:
1,2,3,4,5,6,7,8,9,10,11
(5).表达式树
一串表达式可以构成一个特殊的树——表达式树;
例如这串表达式:
构成的表达式树为:
可以通过先序遍历,中序遍历和后序遍历来构造前缀表达式(波兰式),中缀表达式和后缀表达式(逆波兰式);
(6).前缀表达式(波兰式)
前缀表达式(波兰式)是通过先序遍历构成的,例如上图,构成的前缀表达式为:
(7).中缀表达式
中缀表达式是通过中序遍历构成的,例如上图,构成的中缀表达式为:
可以发现,中缀表达式就是我们平常用的算式;
(8).后缀表达式(逆波兰式)
后缀表达式(逆波兰式)是通过后序遍历构成的,例如上图,构成的后缀表达式为:
(9).前缀表达式与后缀表达式的用处
前缀表达式与后缀表达式一般适用于计算机,由于这两个表达式不需要括号,所以可以用栈来实现;
4.二叉树的深度优先搜索与广度优先搜索
(1).二叉树的深度优先搜索
二叉树的深度优先搜索(DFS,简称深搜)一般是求先序遍历,中序遍历或者后序遍历;
深度优先搜索的逻辑为:一直往下搜,直到没有路为止,然后回溯,继续找路;
注:第3节已经给了代码,这里不过多赘述;
(2).二叉树的广度优先搜索
二叉树的广度优先搜索(BFS,简称广搜,也称宽度优先搜索,简称宽搜)一般是求层序遍历,大多数情况下是没有什么意义的;
广度优先搜索的逻辑为:每搜到一个节点就回头再找上一轮的节点继续搜索,和火灾蔓延相似;
广度优先搜索需要使用队列来遍历:
queue<node> the_queue; // STL
void bfs(){
the_queue.push(root);
while(!the_queue.empty()){
if(the_queue.front().left != NULL)
the_queue.push(the_queue.front().left);
if(the_queue.front().right != NULL)
the_queue.push(the_queue.front().right);
the_queue.pop();
}
}
注:此代码仅二叉树可用;