package com.datastructure;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
/**
* 二叉树(BinaryTree):
* 二叉树的基本单元是节点;
* 每个节点包含值、左子节点引用和右子节点引用;
*
* 在二叉树中,除叶节点外,其他所有节点都包含子节点和非空子树
*
*
* 二叉树常见术语:
* 1.根节点(root node):位于二叉树顶层的节点,没有父节点
* 2.叶节点(leaf node):没有子节点的节点,其两个指针均指向None.
* 3.边(edge):连接两个节点的线段,即节点引用(指针)
* 4.节点所在的层(level):从顶至底递增,跟节点所在层为1
* 5.节点的度(degree):节点的字节点的数量.在二叉树中,度的取值范围是0,1,2
* 6.二叉树的高度(height):从根节点到最远叶节点所经过的边的数量
* 7.节点的深度(depth):从根节点到该节点所经过的边的数量
* 8.节点的高度(height):从距离该节点最远的叶节点到该节点所经过的边的数量
*
* 常见二叉树类型:
* 1.完美二叉树/满二叉树(perferct binary tree):所有层的节点都被完美填满;在完美二叉树中,叶节点的度为0,其余所有节点的度为2;
* 2.完全二叉树(complate binary tree):只有最底层的节点未被填满,且最底层节点尽量靠左填充
* 3.完满二叉树(full binary tree):除了叶节点之外,其余所有节点都有两个子节点; 所有节点的度都为0或2
* 4.平衡二叉树(balanced binary tree):任意节点的左子树和右子树的高度之差的绝对值不超过1
*
* 二叉树的遍历方式:层序遍历、前序遍历、中序遍历、后序遍历
*/
public class BinaryTree {
public static void main(String[] args) {
//1.初始化二叉树:首先初始化节点,然后构建引用(指针)
//初始化节点
TreeNode n1=new TreeNode(1);
TreeNode n2=new TreeNode(2);
TreeNode n3=new TreeNode(3);
TreeNode n4=new TreeNode(4);
TreeNode n5=new TreeNode(5);
//构建节点之间的引用(指针)
n1.left=n2;
n1.right=n3;
n2.left=n4;
n2.right=n5;
//2.插入与删除节点:在二叉树中插入与删除节点可以通过修改指针来实现
TreeNode p=new TreeNode(0);
//在n1->n2中间插入节点p
n1.left=p;
p.left=n2;
//删除节点p
n1.left=n2;
}
}
class TreeNode{
int val;//节点值
TreeNode left;//左子节点引用
TreeNode right;//右子节点引用
public TreeNode(int x){
this.val=x;
}
}
/**
* 1.层序遍历(level-order traversal):
* 从顶部到底部逐层遍历二叉树,并在每一层按照从左到右的顺序访问节点;
* 层序遍历本质上属于广度优先遍历(Breadth-first-traversal),也称广度优先搜索(breadth-first search BFS),
* 体现的是一圈一圈向外扩展的逐层遍历的方式;
* 广度优先遍历实现通常借助队列来实现。
* 2.前序、中序、后序遍历都属于深度优先遍历(depth-frist-traversal),也称深度优先搜索(depth-frist-search DFS),体现了一种先走到尽头,再回溯继续的遍历方式;
* 深度优先遍历就像绕着整颗二叉数的外围走一圈.每个节点都会遇到三个位置,分别对应前序遍历、中序遍历、后序遍历
* 深度优先搜索通常基于递归实现
*/
class BinaryTreeBFS{
/**
*1. 层序遍历
* 时间复杂度为O(n)
*/
public List<Integer> levelOrder(TreeNode root){
//初始化队列,加入根节点
Queue<TreeNode> queue=new LinkedList<>();
queue.add(root);
//初始化一个列表,用于保存遍历序列
List<Integer> list=new ArrayList<>();
while (!queue.isEmpty()){
TreeNode node=queue.poll();//队列出队
list.add(node.val);//保存节点值
if(node.left!=node){
queue.offer(node.left);//左子节点入队
}
if(node.right!=node){
queue.offer(node.right);//有子节点入队
}
}
return list;
}
/**
* 2.前序遍历
* 访问方式:根->左->右
*/
public void preOrder(TreeNode root) {
//初始化一个列表,用于保存遍历序列
List<Integer> list = new ArrayList<>();
if (root == null)
return;
list.add(root.val);
preOrder(root.left);
preOrder(root.right);
}
/**
* 3.中序遍历
* 访问方式:左->根->右
*/
public void inOrder(TreeNode root){
List<Integer> list = new ArrayList<>();
if(root==null)
return;
inOrder(root.left);
list.add(root.val);
inOrder(root.right);
}
/**
* 4.后序遍历
* 访问方式:左->右->根
*/
public void postOrder(TreeNode root){
List<Integer> list = new ArrayList<>();
if(root==null)
return;
postOrder(root.left);
postOrder(root.right);
list.add(root.val);
}
}
/**
* 二叉树类:数组表示
*
* 左子节点的索引 2i+1;
* 右子节点的索引 2i+2;
*
* 二叉树的数组表示优缺点
* 优点:
* 数组存储在连续的内存空间中,对缓存友好,访问与遍历速度较快。
* 不需要存储指针,比较节省空间。
* 允许随机访问节点。
*
* 缺点:
* 数组存储需要连续内存空间,因此不适合存储数据量过大的树。
* 增删节点需要通过数组插入与删除操作实现,效率较低。
* 当二叉树中存在大量 None 时,数组中包含的节点数据比重较低,空间利用率较低
*/
class ArrayBinaryTree{
private List<Integer> tree;
/**
* 构造方法
*/
public ArrayBinaryTree(List<Integer> arr){
tree=new ArrayList<>(arr);
}
/**
* 列表容量
*/
public int size(){
return tree.size();
}
/**
* 获取索引为i节点的值
*/
public Integer val(int i){
//若索引越界,则返回null,代表空位
if(i<0|| i>=size())
return null;
return tree.get(i);
}
/**
* 获取索引为i节点的左子节点的索引
*/
public Integer left(Integer i){
return 2*i+1;
}
/**
* 获取索引为i节点的右子节点的索引
*/
public Integer right(int i){
return 2*i+2;
}
/**
* 获取索引为i节点的父节点的索引
*/
public Integer parent(int i){
return (i-1)/2;
}
/**
* 层序遍历
*/
public List<Integer> levelOrder(){
List<Integer> res=new ArrayList<>();
//直接遍历数组
for(int i=0;i<size();i++){
if(val(i)!=null)
res.add(val(i));
}
return res;
}
/**
* 深度优先遍历
*/
public void dfs(Integer i,String order,List<Integer> res){
//若未空未,返回
if(val(i)==null)
return;
//前序遍历
if("pre".equals(order)){
res.add(val(i));
}
dfs(left(i),order,res);
//中序遍历
if("in".equals(order)){
res.add(val(i));
}
dfs(right(i),order,res);
//后序遍历
if ("post".equals(order)){
res.add(val(i));
}
}
/**
* 前序遍历
*/
public List<Integer> preOrder(){
List<Integer> res=new ArrayList<>();
dfs(0,"pre",res);
return res;
}
/**
* 中序遍历
*
*/
public List<Integer> inOrder(){
List<Integer> res=new ArrayList<>();
dfs(0,"in",res);
return res;
}
/**
* 后序遍历
*/
public List<Integer> postOrder(){
List<Integer> res=new ArrayList<>();
dfs(0,"post",res);
return res;
}
}
详解二叉树的实现
于 2024-01-30 11:35:22 首次发布