顺序储存二叉树
特点
- 顺序二叉树通常只考虑完全二叉树
- 第n个元素的左节点为 2 * n + 1
- 第n个元素的右节点为 2 * n + 2
- 第n个元素的父节点为 (n-1) /2
案例
package com.example.dataalgorithm.tree;
/**
* @author qb
* @version 1.0
* @since 2022/3/2 14:42
*/
public class ArrBinaryTreeDemo {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6,7};
ArrBinaryTree arrBinaryTree = new ArrBinaryTree(arr);
arrBinaryTree.preOrder();
}
}
/**
* 顺序存储二叉树
*/
class ArrBinaryTree{
/**
* 存储数据节点
*/
private int[] arr;
public ArrBinaryTree(int[] arr) {
this.arr = arr;
}
public void preOrder(){
this.preOrder(0);
}
/**
* 编写一个方法,完成顺序存储二叉树的前续遍历
* @param index 数组下标
*/
public void preOrder(int index){
if(null == arr || arr.length == 0){
System.out.println("数组为空,不能按照二叉树的前序遍历");
return;
}
//输出当前的数组元素
System.out.println(arr[index]);
//向左递归遍历
if((index*2 + 1) < arr.length){
preOrder(2*index+1);
}
if((index * 2 + 2) < arr.length){
preOrder(index*2 + 2);
}
}
}
线索化二叉树
案例
package com.example.dataalgorithm.tree.threadedBinaryTree;
import lombok.Data;
/**
* 线索化二叉树
*
* @author qb
* @version 1.0
* @since 2022/3/2 15:12
*/
public class ThreadedBinaryTreeDemo {
public static void main(String[] args) {
HeroNode root = new HeroNode(1, "tom");
HeroNode node2 = new HeroNode(3, "jack");
HeroNode node3 = new HeroNode(6, "smith");
HeroNode node4 = new HeroNode(8, "mary");
HeroNode node5 = new HeroNode(10, "king");
HeroNode node6 = new HeroNode(14, "dim");
root.setLeft(node2);
root.setRight(node3);
node2.setLeft(node4);
node2.setRight(node5);
node3.setLeft(node6);
BinaryTree binaryTree = new BinaryTree();
binaryTree.setRoot(root);
binaryTree.threadedNodes();
//测试 以10号测试
HeroNode heroNode = node5.getLeft();
System.out.println("10号节点的前驱结点:"+heroNode);
System.out.println("10号节点的后继结点:"+node5.getRight());
}
}
/**
* 树,线索化二叉树
*/
class BinaryTree{
private HeroNode root;
/**
* 为了实现线索化,需要创建要给指向当前节点的前驱节点的指针
* 在递归进行线索化时,总是保留前一个节点
*/
private HeroNode pre = null;
public void setRoot(HeroNode root) {
this.root = root;
}
public void threadedNodes(){
threadedNodes(root);
}
/**
* 编写对二叉树进行中序线索化的方法
* @param node 就是当前需要线索化的节点
*/
public void threadedNodes(HeroNode node){
if(null == node){
return;
}
//1.先线索化左子树
threadedNodes(node.getLeft());
//2.线索化当前节点 [ 有难度 ]
//2.1 先处理当前节点的前驱节点
if(node.getLeft() == null){
//就让当前节点的左指针,指向前驱节点
node.setLeft(pre);
//修改当前节点的左指针的类型
node.setLeftType(1);
}
//2.2 处理当前节点的后继节点
if(null != pre && null == pre.getRight()){
//让前驱节点的右指针指向当前节点
pre.setRight(node);
//修改当前节点的右指针类型
pre.setRightType(1);
}
//!!!!每处理一个节点,让当前节点是下一个节点的去前驱节点
pre = node;
//3.线索化右子树
threadedNodes(node.getRight());
}
/**
* 前序遍历
*/
public void preOrder(){
if(null != this.root){
this.root.preOrder();
}else{
System.out.println("当前二叉树为空,无法遍历");
}
}
public void infixOrder(){
if(null != this.root){
this.root.infixOrder();
}else{
System.out.println("当前二叉树为空,无法遍历");
}
}
public void postOrder(){
if(null != this.root){
this.root.postOrder();
}else{
System.out.println("当前二叉树为空,无法遍历");
}
}
public HeroNode preOrderSearch(int no){
if(null != this.root){
return this.root.preOrderSearch(no);
}else{
return null;
}
}
public HeroNode infixOrderSearch(int no){
if(null != this.root){
return this.root.infixOrderSearch(no);
}else{
return null;
}
}
public HeroNode postOrderSearch(int no){
if(null != this.root){
return this.root.postOrderSearch(no);
}else{
return null;
}
}
public void delNode(int no){
if(null != root){
if(root.getNo() == no){
root = null;
}else{
this.root.delNode(no);
}
}else {
System.out.println("树为空");
}
}
}
/**
* 节点
*/
@Data
class HeroNode{
private int no;
private String name;
private HeroNode left;
private HeroNode right;
/**
* 1. 如果leftType == 0 表示指向的事左子树,如果 1 则表示指向前驱节点
* 2. 如果rightType == 0 表示指向右子树,如果 1 表示指向 后继节点
*/
private int leftType;
private int rightType;
public HeroNode(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
/**
* 前续遍历方法
*/
public void preOrder(){
//先输出根节点
System.out.println(this);
//递归左子树
if(null != this.left){
this.left.preOrder();
}
//递归向右
if(null != this.right){
this.right.preOrder();
}
}
/**
* 中序遍历
*/
public void infixOrder(){
//递归左子树
if(null != this.left){
this.left.infixOrder();
}
//先输出根节点
System.out.println(this);
//递归向右
if(null != this.right){
this.right.infixOrder();
}
}
/**
* 后续遍历
*/
public void postOrder(){
//递归左子树
if(null != this.left){
this.left.postOrder();
}
//递归向右
if(null != this.right){
this.right.postOrder();
}
//先输出根节点
System.out.println(this);
}
/**
* 前续遍历查找
* @param no 查找的编号
* @return HeroNode 节点
*/
public HeroNode preOrderSearch(int no){
System.out.println("进入前序遍历"+no);
if(no == this.no){
return this;
}
HeroNode resNode = null;
if(null != this.left){
resNode = this.left.preOrderSearch(no);
}
if(null != resNode){
return resNode;
}
if(null != this.right){
resNode = this.right.preOrderSearch(no);
}
return resNode;
}
/**
* 中续遍历查找
* @param no 查找的编号
* @return HeroNode 节点
*/
public HeroNode infixOrderSearch(int no){
HeroNode resNode = null;
if(null != this.left){
resNode = this.left.infixOrderSearch(no);
}
if(null != resNode){
return resNode;
}
System.out.println("进入中续遍历");
if(no == this.no){
return this;
}
if(null != this.right){
resNode = this.right.infixOrderSearch(no);
}
return resNode;
}
/**
* 后续遍历查找
* @param no 查找的编号
* @return HeroNode 节点
*/
public HeroNode postOrderSearch(int no){
HeroNode resNode = null;
if(null != this.left){
resNode = this.left.postOrderSearch(no);
}
if(null != resNode){
return resNode;
}
if(null != this.right){
resNode = this.right.postOrderSearch(no);
}
if(null != resNode){
return resNode;
}
System.out.println("进入后续遍历");
if(no == this.no){
return this;
}
return resNode;
}
/**
* 递归删除节点
*/
public void delNode(int no){
if(null != this.left && this.left.no == no){
this.left = null;
return;
}
if(null != this.right && this.right.no == no){
this.right = null;
return;
}
if(null != this.left){
this.left.delNode(no);
}
if(null != this.right){
this.right.delNode(no);
}
}
}
遍历
public void threadedList(){
//定义一个变量,存储当前遍历的节点,从root开始
HeroNode node = root;
while (node != null)
{
//循环找到leftType == 1 的节点,第一个找到的是8节点
//后面随着遍历而变化,当left==1的时候,说明该节点是按照线索化,处理后的有效节点
while (node.getLeftType() == 0){
node = node.getLeft();
}
//打印当前节点
System.out.println(node);
//如果当前节点的右指针,指向的是后继节点,就一直输出
while (node.getRightType() == 1)
{
//获取到当前节点的后继节点
node = node.getRight();
System.out.println(node);
}
//替换这个遍历的节点
node = node.getRight();
}
}