二叉树的数组表示:
一、数据结构的本质
二叉树在很多应用的地方,其实很多时候并不需要去建树。大多数学生陷入一个误区,二叉树一定要形如下面的样子。
package tree; public class BinaryTree <T>{ private Node root; class Node{ T data; Node left; Node right; Node(T data){ this.data=data; this.left=null; this.right=null; } } public BinaryTree(){ root = new Node(null); } /** * 各种遍历 */ }
这其实在某种程度上陷入了一个误区。认为只要是树就长这样。其实树还可以这样定义。
public class BinaryTree{ int[] tree; /** * @param num 结点数 */ public BinaryTree(int num) { tree = new int[num]; }; /** * 其他方法 */ public ...{ 。。。 } }
有些朋友可能会奇怪。为什么树还可以这么定义呢?和书上教的并不一样啊。
其实数据结构只是一种思维,一种思想,我们用多种方法来实现这种思想。
二、实际应用。
对于任何数据结构来说,没有实际应用都是纸上谈兵。
这时,我挑选了一道题。题目选自算法竞赛入门经典。
样例输入: 4 2 3 4 10 1 2 2 8 128 16 12345 样例输出: 12 7 512 3 255 36358
分析这道题。如果对这个题目进行建树,那我们需要写出很多很多代码,首先要定义数据结构,其次要根据数据结构定义对应的方法。
这无疑对我们来说是很头疼的一件事。那么对于此次实现,我们应该定义 俩个规则:
一、二叉树的俩个子节点与索引的关系
对于索引为K的节点,其左孩子为(2*K) 右孩子为( 2*K+1)
二、二叉树的根节点位置
为了方便编程,我们设置根节点的索引为1 即root = Tree[1]
然后根据此题逻辑,我们稍加思考即可写出以下代码
package first; import java.util.Scanner; /** * @author GodofOrange * @算法竞赛入门经典:P149 */ public class A { // 树的数组 对于任何一个节点索引K // 索引K==0不参与此次算法 // 其左子节点和右子节点的编号为2K和2K+1 // Tree false=关闭 true=打开 public static boolean[] Tree = new boolean[2 << 20 - 1]; public static void main(String[] args) { Scanner sc = new Scanner(System.in); int D = sc.nextInt(); int I = sc.nextInt(); int K = 0; // 让N个小球落下 for (int i = 0; i < I; i++) { K= 1; while(true) { //小球滑到该处 将true改成false; Tree[K] = !Tree[K]; //如果Tree[K]=true 往左滑,否则往右滑 K = Tree[K] ? K*2:K*2+1; if(K>(2<<D-1)-1)break; } } sc.close(); System.out.println(K/2); } }
这是运行后的结果。
三、总结
无论何种数据结构,都可以有很多种实现方法,不一定非得像书中定义的ADT那种格式,也不要将思想局限于此。