目录
1. 什么是二叉树
2. 二叉树的性质
3. 二叉树的分类:
3.1. 满二叉树:
3.2. 完全二叉树
4. 二叉树的存储方式
4.1 顺序存储
4.2 链式存储
5. 二叉树的遍历
5.1 前序遍历:
5.2 中序遍历:
5.3 后序遍历
5.4 层次遍历
满足以下两个条件的树称之为二叉树:
1. 本质上为有序树;
2. 每个结点的度不能超过2,即结点的度仅能为0,1,2。
性质1:二叉树第i层的结点数最多为2^(i-1) (i>=1)。
性质2:深度为k的二叉树最多有2^k - 1个结点。
性质3:在任意一颗二叉树中,若终端结点(叶子结点)的个数为n0,度为2的结点树为n2,则n0=n2+1。
证明:设二叉树中度为1的结点数为n1,结点总数为n,则n = n0 + n1 +n2。同时,度为2的子结点共有2*n2个,度为1的子结点共有n1个,总结点数=子结点数+根结点 故n = n2*2 + n1 +1。两等式联立得出n0 = n2 +1。
若二叉树中除了叶子结点,每一个节点的度都为2,则称此二叉树为满二叉树。
满二叉树具有以下性质:
1. 满二叉树的第i层结点数为2^(i-1);
2. 深度为k的满二叉树有2^k - 1个结点,叶子结点有2^(k-1)个;
3. 具有n个结点的满二叉树的深度为log2(n+1);
4. 满二叉树中不存在度为1的结点,叶子结点仅存在在最底层。
若二叉树除了最后一层结点满足满二叉树的定义,且最后一层节点满足从左到右分布的次序,则该二叉树被称为完全二叉树。
完全二叉树除了满足普通二叉树的性质外,还满足以下性质:
1. n个结点的完全二叉树的深度为⌊log2n⌋+1;
2. 将完全二叉树按照层次从左到右编号,
(1)当i > 1时,序号为i的结点的父结点为结点[i / 2];
(2)若2*i > n, 则序号为i的结点无左子女结点,否则该节点的左子女结点序号为2*i;
(3)若2*i+1>n,则序号为i的结点无右子女结点,否则该结点的右子女结点的序号为2*i+1。
二叉树的存储方式有两种,顺序存储和链式存储。
顺序存储只适用于完全二叉树,若想存储普通二叉树,需要先将其转化为完全二叉树。满二叉树也是一种特殊的完全二叉树。
普通二叉树转化成完全二叉树的方法如下
对于完全二叉树的存储,仅需对其从根节点开始仅需编号,使用数组存储编号即可。取出式依据完全二叉树由左到右分布的性质恢复即可。
顺序存储会造成一定程度上的空间浪费,链式存储可以很好地解决这个问题。链式存储中每个结点包含三部分:左孩子结点、数据域和右孩子结点。
链式存储的JAVA实现为:
class tListnode{
int val;
tListnode leftChild;
tListnode rightChild;
tListnode(){
}
tListnode(int val){
this.val = val;
}
}
二叉树的遍历指从根结点出发,按照某种次序依次访问二叉树中所有的结点,每个结点被访问的次数有且仅有一次。
二叉树存在四种遍历方式:前序遍历、中序遍历、后序遍历和层次遍历
前序遍历的思想是:(根左右)
1. 先访问根结点;
2. 访问当前结点的左子树;
3. 访问当前结点的右子树。
以上图为例,遍历顺序为:
A -> B -> D -> E -> C -> F -> G
JAVA实现:
1. 递归实现
public static void preOrderTraversal(tListnode root){
if(root==null){
return;
}
System.out.println(root.val);
preOrderTraversal(root.leftChild);
preOrderTraversal(root.rightChild);
}
2. 非递归实现
基于栈的实现方式
public static void preOrderTraversal(tListnode root){
Stack stack = new Stack<>();
tListnode cur = root;
while (!stack.empty() || cur!=null){
while (cur!=null){
stack.push(cur);
System.out.println(cur.val);
cur = cur.leftChild;
}
cur = stack.pop();
cur = cur.rightChild;
}
}
中序遍历的思路是:(左根右)
遇到一个节点,先缓存,看其是否有左子节点,若有,则输出左节点,再输出原节点,最后输出右节点。
该二叉树的中序遍历顺序为:
D -> B -> E ->A -> F -> C -> G
JAVA实现
1. 递归实现
public static void inOrderTraversal(tListnode root){
if(root==null){
return;
}
inOrderTraversal(root.leftChild);
System.out.println(root.val);
inOrderTraversal(root.rightChild);
}
2. 非递归实现
基于栈的实现
public static void inOrderTraversal(tListnode root){
Stack stack = new Stack<>();
tListnode cur= root;
while(!stack.empty() || cur!=null){
while (cur!=null){
stack.push(cur);
cur = cur.leftChild;
}
cur = stack.pop();
System.out.println(cur.val);
cur = cur.rightChild;
}
}
后续遍历的思路是:(左右根)
遇到一个节点,先缓存,看它是否存在左子节点,有则输出,接着看其是否有右子结点,最后输出原节点。
该二叉树的后序遍历顺序为:
D -> E -> B -> F -> G -> C ->A
JAVA实现
1. 递归实现
public static void postOrderTraversal(tListnode root){
if(root==null){
return;
}
postOrderTraversal(root.leftChild);
postOrderTraversal(root.rightChild);
System.out.println(root.val);
}
2. 非递归实现
运用双栈
public static void postOrderTraversal(tListnode root){
Stack stack = new Stack<>();
Stack flag = new Stack<>();
tListnode cur = root;
int left = 1;
int right = 2;
while(!stack.empty()||cur!=null){
while (cur!=null){
stack.push(cur);
flag.push(left);
cur = cur.leftChild;
}
while(!stack.empty() && flag.peek()==right){
flag.pop();
System.out.println(stack.pop().val);
}
if(!stack.empty()&&flag.peek()==left){
flag.pop();
flag.push(right);
cur = stack.peek().rightChild;
}
}
}
按照二叉树的层次从上至下从左至右进行遍历。
该二叉树的层次遍历顺序为:
A -> B -> C -> D -> E -> F ->G
实现思路:
1. 根结点入队;
2. 根结点出队,若其存在左子结点,左子结点入队;若其存在右子结点,右子结点出队;
3. 重复1,2直至队列为空。
JAVA实现:
public static void levelOrderTraversal(tListnode root){
Queue queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()){
tListnode cur = queue.poll();
System.out.println(cur.val);
if(cur.leftChild!=null){
queue.add(cur.leftChild);
}
if(cur.rightChild!=null){
queue.add(cur.rightChild);
}
}
}
参考链接:
什么是二叉树,二叉树及其性质详解
二叉树(Java实现) - 卑微芒果 - 博客园
java实现简单二叉树_公号:一条coding-CSDN博客_java 二叉树
二叉树的四种遍历方式 - 林海杜 - 博客园