二叉树
一、概念及其定义
二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树。
二、基本形态
二叉树是递归定义的,其结点有左右子树之分,逻辑上二叉树有五种基本形态:
1、空二叉树——如图(a);
2、只有一个根结点的二叉树——如图(b);
3、只有左子树——如图(c);
4、只有右子树——如图(d);
5、完全二叉树——如图(e)。
三、特殊类型
1、满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树 。
2、完全二叉树:深度为k,有n个结点的二叉树当且仅当其每一个结点都与深度为k的满二叉树中编号从1到n的结点一一对应时,称为完全二叉树 。
完全二叉树的特点是叶子结点只可能出现在层序最大的两层上,并且某个结点的左分支下子孙的最大层序与右分支下子孙的最大层序相等或大1。
四、性质
二叉树特殊的结构导致它有着一些良好的性质:
性质1:二叉树的第i层上至多有2i-1(i≥1)个节点 。
性质2:深度为h的二叉树中至多含有2h-1个节点 。
性质3:若在任意一棵二叉树中,有n0个叶子节点,有n2个度为2的节点,则必有n0=n2+1 。
性质4:具有n个节点的完全二叉树深为log2x+1(其中x表示不大于n的最大整数)。
性质5:若对一棵有n个节点的完全二叉树进行顺序编号(1≤i≤n),那么,对于编号为i(i≥1)的节点:
当i=1时,该节点为根,它无双亲节点 。
当i>1时,该节点的双亲节点的编号为i/2 。
若2i≤n,则有编号为2i的左节点,否则没有左节点 。
若2i+1≤n,则有编号为2i+1的右节点,否则没有右节点 。
四、代码实现思路
标准STL库中没有提供现成的关于二叉树的模板,一般我们会选用数组、结构体、指针等来模拟一个二叉树,实现一些简单的功能,如:增、删、改、查。
1、建树
(1)根据存储值做索引:
- 创建两个数组:left、right;
- 将根节点存储值作为数组下标分别将其左子节点存储的值和右子节点存储的值存入left、right数组对应下标处;
- 再根据子节点的值做下标依照上述过程存储其子节点的值,以此类推;
(2)根据索引特征做索引: - 创建三个数组:root、left、right;
- root[idx]=value1;
- root[idx*2]=left[idx]=value2;
- root[idx*2+1]=right[idx]=value3;
- idx=idx*2 ;
- 重复上述过程;
2、3 改和删
比较容易实现,删则可以看作一种特殊的改,将其值改为0即可。
4、遍历
- 前序遍历:根->左->右;
- 中序遍历:左->根->右;
- 后序遍历:左->右->根;
(要用到递归的思想)
//前序遍历:
void traverse(int val){
cout<<val;
if(left[val]!=0) traverse(left[val]);//递归思想
if(righet[val]!=0) traverse(right[val]);
}
//中序遍历:
void traverse(int val){
if(left[val]!=0) traverse(left[val]);//递归思想
cout<<val;
if(righet[val]!=0) traverse(right[val]);
}
//后序遍历:
void traverse(int val){
if(left[val]!=0) traverse(left[val]);//递归思想
if(righet[val]!=0) traverse(right[val]);
cout<<val;
}
可以根据这个思路去理解:
当满足条件时,调用traverse()函数,即打开了一个有新的值的新的窗口,在这个窗口里再次只需判断等。当执行完或者是不符合条件时会停止这个窗口,沿着这个窗口找到上一个窗口的端口,再继续执行上一个窗口没有执行的指令,依次类推。
(PS:附两张图片帮助大家理解递归)