8. 数据结构之顺序储存二叉树

tech2024-08-19  38

文章目录

数据结构之顺序储存二叉树1. 顺序储存二叉树1.1 顺序存储二叉树的概念1.2 顺序存储二叉树的特点☆1.3 顺序存储二叉树遍历1.3.1 代码实现 2. 线索化二叉树2.1 线索二叉树应用案例2.2 代码实现2.2.1 `HeroNode` 部分2.2.2 `ThreadedBinaryTree` 部分2.2.3 测试 ☆

数据结构之顺序储存二叉树

1. 顺序储存二叉树

1.1 顺序存储二叉树的概念

从数据存储来看,数组存储方式和树的存储方式可以相互转换,即 数组可以转换成树, 树也可以转换成数组。

1.2 顺序存储二叉树的特点☆

顺序二叉树通常只考虑完全二叉树第 n 个元素的左子节点为 2 * n + 1第 n 个元素的右子节点为 2 * n + 2第 n 个元素的父节点为 (n-1) / 2n : 表示二叉树中的第几个元素(按 0 开始编号如图所示)

1.3 顺序存储二叉树遍历

要求在遍历数组 arr 时,仍然可以以前序遍历,中序遍历和后序遍历的方式完成结点的遍历给你一个数组 {1,2,3,4,5,6,7},要求以二叉树前序遍历,中序遍历和后序遍历的方式进行遍历。 前序遍历的结果应当为1,2,4,5,3,6,7中序遍历的结果应当为4 2 5 1 6 3 7后序遍历的结果应当为4 5 2 6 7 3 1
1.3.1 代码实现
public class ArrBinaryTreeDemo { public static void main(String[] args) { //测试 int[] arr = {1,2,3,4,5,6,7}; //创建一个ArrBinaryTree ArrBinaryTree arrBinaryTree = new ArrBinaryTree(arr); System.out.println("顺序储存的二叉树的前序遍历:"); arrBinaryTree.preOrder();//1 2 4 5 3 6 7 System.out.println("顺序储存的二叉树的中序遍历:"); arrBinaryTree.infixOrder();// 4 2 5 1 6 3 7 System.out.println("顺序储存的二叉树的后序遍历:"); arrBinaryTree.postOrder();// 4 5 2 6 7 3 1 } } /** * 编写一个ArrBinaryTree实现顺序储存二叉树遍历 * * @author DuanChaojie * @date 2020年3月14日 下午1:28:28 * @version 1.0 */ class ArrBinaryTree { private int[] arr;// 储存数据节点的数组 public ArrBinaryTree(int[] arr) { this.arr = arr; } //方法的重载 public void preOrder() { this.preOrder(0); } public void infixOrder() { this.infixOrder(0); } public void postOrder() { this.postOrder(0); } /** * 顺序储存数组的前序遍历 * @param index 数组的下标 */ public void preOrder(int index) { // 如果数组为空,或者arr.length = 0 if (arr == null || arr.length == 0) { System.out.println("数组为空,不能按照二叉树的前序遍历"); } // 输出当前这个元素 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)); } } /** * 顺序储存数组的中序遍历 * @param index 数组的下标 */ public void infixOrder(int index) { // 如果数组为空,或者arr.length = 0 if (arr == null || arr.length == 0) { System.out.println("数组为空,不能按照二叉树的前序遍历"); } // 向左递归遍历 if ((index * 2 + 1) < arr.length) { infixOrder((index * 2 + 1)); } // 输出当前这个元素 System.out.println(arr[index]); // 向右递归遍历 if ((index * 2 + 2) < arr.length) { infixOrder((index * 2 + 2)); } } /** * 顺序储存数组的后序遍历 * @param index 数组的下标 */ public void postOrder(int index) { // 如果数组为空,或者arr.length = 0 if (arr == null || arr.length == 0) { System.out.println("数组为空,不能按照二叉树的前序遍历"); } // 向左递归遍历 if ((index * 2 + 1) < arr.length) { postOrder((index * 2 + 1)); } // 向右递归遍历 if ((index * 2 + 2) < arr.length) { postOrder((index * 2 + 2)); } // 输出当前这个元素 System.out.println(arr[index]); } }

2. 线索化二叉树

n 个结点的二叉链表中含有 n+1 【公式 2n-(n-1)=n+1】 个空指针域。利用二叉链表中的空指针域,存放指向该结点在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为"线索")这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree)。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种一个结点的前一个结点,称为 前驱结点一个结点的后一个结点,称为后继结点

2.1 线索二叉树应用案例

将下面的二叉树,进行中序线索二叉树。中序遍历的数列为 {8, 3, 10, 1, 14, 6}

当线索化二叉树后,Node 节点的 属性 left 和 right ,有如下情况:

left 指向的是左子树,也可能是指向的前驱节点. ① 节点 left 指向的左子树, ⑩ 节点的 left 指向的就是前驱节点right 指向的是右子树,也可能是指向后继节点。 ① 节点 right 指向的是右子树 ⑩ 节点的 right 指向的是后继节点

2.2 代码实现

2.2.1 HeroNode 部分
如果 leftType == 0 表示指向的是左子树,如果是1 表示指向的是前驱节点如果 rightType == 0 表示指向是右子树, 如果 1 表示指向后继结点 /** *创建HeroNode节点 * */ class HeroNode{ private int no; private String name; private HeroNode left;//默认为null private HeroNode right;//默认为null //1. 如果leftType == 0 表示指向的是左子树,如果是1 表示指向的是前驱节点 //2. 如果 rightType == 0 表示指向是右子树, 如果 1 表示指向后继结点 private int leftType; private int rightType; //构造器 public HeroNode(int no, String name) { super(); this.no = no; this.name = name; } //get和set方法 //省略.... //重写toString方法 @Override public String toString() { return "HeroNode [no=" + no + ", name=" + name + "]"; } //....... }
2.2.2 ThreadedBinaryTree 部分

public void threadedList();遍历线索化二叉树的方法

public void threadedNode();

public void threadedNode(HeroNode node);

/** * 定义ThreadedBinaryTree 实现了线索化功能的二叉树 * @author Administrator * @date 2020年3月14日 下午1:21:01 * @version 1.0 */ class ThreadedBinaryTree{ private HeroNode root; private HeroNode pre = null; /* * 为了实现线索化,需要创建要给指向当前节点的前驱节点的指针 * 在递归进行线索化时,pre 总是保留前一个节点 * */ //get和set方法 public HeroNode getRoot() { return root; } public void setRoot(HeroNode root) { this.root = root; } public HeroNode getPre() { return pre; } public void setPre(HeroNode pre) { this.pre = pre; } /** *遍历线索化二叉树的方法 */ public void threadedList() { //定义一个变量,存储当前遍历的节点,从root开始 HeroNode node = root; while(node != null) { //循环找到leftType == 1的节点,从root开始 //后面随着遍历的变化,因为当leftType==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(); } } //重载的方法 public void threadedNode() { this.threadedNode(root); } /** * * @param node 当前需要线索化的节点 */ public void threadedNode(HeroNode node) { //如果node == null 不能线索化 if(node == null) { return; } //先线索化左子树 threadedNode(node.getLeft()); //线索化当前节点 //处理当前节点的前驱节点 if(node.getLeft() == null) { //让当前节点的左指针指向前驱节点 node.setLeft(pre); //修改当前节点的左指针的类型,指向前驱节点 node.setLeftType(1); } //处理后继节点 if(pre != null && pre.getRight() == null) { //让前驱节点的右指针指向当前节点 pre.setRight(node); //修改前驱节点的右指针 pre.setRightType(1); } //每处理一个节点,让当前节点是下一个节点的前驱节点 pre = node; //线索化右子树 threadedNode(node.getRight()); } //..... }
2.2.3 测试
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); //测试中序线索化 ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree(); threadedBinaryTree.setRoot(root); threadedBinaryTree.threadedNode(); //测试: 以 10 号节点测试 HeroNode leftNode = node5.getLeft(); HeroNode rightNode = node5.getRight(); System.out.println("10 号结点的前驱结点是 =" + leftNode); //3 System.out.println("10 号结点的后继结点是=" + rightNode); //1 //当线索化二叉树后,能在使用原来的遍历方法 //threadedBinaryTree.infixOrder(); System.out.println("使用线索化的方式遍历 线索化二叉树"); threadedBinaryTree.threadedList(); // 8, 3, 10, 1, 14, 6 } }

最新回复(0)