树结构
树的数据结构
数组:用下标方式访问元素,查找速度快,插入和删除速度慢
链表:插入和删除的速度较快,在检索时效率较低
树存储:存储和读取效率很高,插入,删除,修改的速度也可以保证
常用术语:
树的高度:最大层数
森林:多棵子树构成森林
二叉树的概念
每个节点最多有两个子节点的树叫做二叉树,它的子节点分为左子节点和右子节点。
二叉树所有叶子节点都在最后一层,节点总数为2^n-1,n为层数,称为满二叉树。
二叉树所有叶子节点都在最后一层或倒数第二层,最后一层叶子节点在左边连续,倒数第二层叶子节点在右边连续,我们称为完全二叉树。
写一个二叉树的思路
- 创建两个类:heroNode,BinaryTree
- heroNode本身要包含前序中序后序遍历的代码,BinaryTree中要包含一个root节点作为树的根,在初始化的时候就要加入进去,还要包含实现遍历的代码(调用heroNode中的)
二叉树的遍历
前序遍历:输出顺序 父节点-左子树-右子树
中序遍历:输出顺序 左子树-父节点-右子树
后序遍历:输出顺序 左子树-右子树-父节点
看父节点的输出顺序决定是哪种遍历
代码实现:
package com.tree;
public class binaryTree {
public static void main(String[] args){
heroNode heroNode1 = new heroNode(1,"nancy1");
heroNode heroNode2 = new heroNode(2,"nancy2");
heroNode heroNode3 = new heroNode(3,"nancy3");
heroNode heroNode4 = new heroNode(4,"nancy4");
heroNode heroNode5 = new heroNode(5,"nancy5");
heroNode1.left = heroNode2;
heroNode1.right = heroNode3;
heroNode3.left = heroNode4;
heroNode3.right = heroNode5;
binaryTreeDemo binaryTreeDemo = new binaryTreeDemo(heroNode1);
System.out.println("前序遍历:");
binaryTreeDemo.preorderTraversal();
System.out.println("中序遍历:");
binaryTreeDemo.inorderTraversal();
System.out.println("后序遍历:");
binaryTreeDemo.postorderTraversal();
}
}
class heroNode{
int id;
String name;
heroNode left;
heroNode right;
public heroNode(int id,String name){
this.id = id;
this.name = name;
}
@Override
public String toString(){
return "HeroNode:"+id+" name: "+name;
}
//前序遍历
public void preorderTraversal(){
System.out.println(this);
if(left!=null){
this.left.preorderTraversal();
}
if(right!=null){
this.right.preorderTraversal();
}
}
//中序遍历
public void inorderTraversal(){
if(left!=null){
this.left.inorderTraversal();
}
System.out.println(this);
if(right!=null){
this.right.inorderTraversal();
}
}
//后序遍历
public void postorderTraversal(){
if(left!=null){
this.left.postorderTraversal();
}
if(right!=null){
this.right.postorderTraversal();
}
System.out.println(this);
}
}
class binaryTreeDemo{
heroNode root;
public binaryTreeDemo(heroNode root){
this.root = root;
}
public void preorderTraversal(){
root.preorderTraversal();
}
public void inorderTraversal(){
root.inorderTraversal();
}
public void postorderTraversal(){
root.postorderTraversal();
}
}
二叉树查找指定节点
中序查找思路:
- 判断当前节点的子节点是否为空,如果不为空,则递归中序查找。
- 如果找到,则返回;
- 如果没找到,和当前节点进行比较,如果是则返回当前节点,如果不是,继续进行右递归的中序查找。
- 如果找到则返回,没找到,返回null
比较核心的想法就是仍然是在遍历整个过程,但是将输出的过程转换为对比的过程,res的赋值是在递归中实现的,当查找到了的时候,递归函数返回一个heroNode,这样就实现了给res赋值HeroNode,实现了查找的功能。
代码:
//中序查找
public heroNode inorderSearch(int no){
heroNode res = null;
if(left!=null){
res = this.left.inorderSearch(no);
}
if(res != null){
return res;
}
//要在进入到对比这里,才需要进行计数
System.out.println("进行了一次对比~~~");
if(this.id == no){
return this;
}
if(right!=null){
res = this.right.inorderSearch(no);
}
if(res != null){
return res;
}
return null;
}
二叉树删除节点
如果删除的是叶子节点,则直接删除;如果是非叶子节点,则删除该子树。
思路分析:
首先处理树为空和只有root一个节点的情况
- 删除树上节点时,需要找到某个节点的子节点为要删除的节点,而不能直接去寻找某个节点是不是要删除的点
- 当前节点的左子节点不为空且为目标节点,this.left = null;
- 当前节点的右子节点不为空且为目标节点,this.right = null;
- 如果节点还没有被删除,且左子树不为空,递归左子树
- 如果还没有被删除,且右子树不为空,递归右子树
代码:
这段代码是在上一段的修改下完成的
//节点类下面加入如下方法
public void del(int no){
if(this.left != null && this.left.id == no){
this.left = null;
return;
}
if (this.right != null && this.right.id == no) {
this.right = null;
return;
}
if (this.left != null) {
this.left.del(no);
}
if (this.right != null) {
this.right.del(no);
}
}
//树类下面加入如下函数
public void del(int no){
if(root == null){
System.out.println("当前树为空~~~");
return;
}
if(root.id == no){
root = null;
System.out.println("root已被删除~~~");
return;
}
root.del(no);
}
顺序存储二叉树
要求:
遍历数组arr时,仍然可以实现前序中序后序遍历。
特点:
- 只考虑完全二叉树
- 第n个元素的左子节点为2*n+1
- 第n个元素的右子节点为2*n+2
- 第n个元素的父节点为(n-1)/2
代码
package com.tree;
public class arrBinaryTree {
public static void main(String[] args){
int[] arr = {1,2,3,4,5,6};
arrBianary arrBianary = new arrBianary(arr);
arrBianary.postOrder();
}
}
class arrBianary{
private int[] arr;
public arrBianary(int[] arr){
this.arr = arr;
}
public void preOrder(int index){
if(arr.length<0 || arr == null)
{
System.out.println("nothing to print!");
return;
}
System.out.println(arr[index]);
if(index*2+1<arr.length){
preOrder(index*2+1);
}
if(index*2+2<arr.length){
preOrder(index*2+2);
}
}
public void postOrder(){
if(arr.length==0 || arr == null)
{
System.out.println("nothing to print!");
return;
}
postOrder(0);
}
private void postOrder(int index){
if(index*2+1<arr.length){
int left = index*2+1;
postOrder(left);
}
if(index*2+2<arr.length){
int right = index*2+2;
postOrder(right);
}
System.out.println(arr[index]);
}
}