Java数据结构之树和二叉树
从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~
Java中的数据结构模型可以分为一下几部分:
1.线性结构
2.树形结构
3.图形或者网状结构
接下来的几章,我们将会分别讲解这几种数据结构,主要也是通过Java代码的方式来讲解相应的数据结构。
今天要讲解的是:Java线性结构
Java数据结构之树形结构
之前我们前几章学习的都是Java数据结构的线性结构,都是一对一的,从现在开始我们将要学习Java的树形结构。
树对于我们来普通Java程序员而言,也许平常的时候我们似乎感觉不到它的存在。但其实不是这样的。
其实是jdk帮我们已经封装好了,所以给我们一种错觉,树这种数据结构似乎离我们很远。
随便举一个例子:TreeMap这种集合框架,底层使用的就是红黑树...
下面对树这种数据结构进行一下简单的介绍(如果想要了解详细的内容的话,请自己百度吧~亲)。
1.树中的节点可以有若干个子节点,但是每个子节点只能有一个父节点。
这就好比一对夫妇可能有多个孩子,但是每个孩子只能有唯一的一对父母。
2.树的分类
按照当前节点是否有父节点可以分为:根节点和普通节点。
按照当前节点是否有子节点可以分为:叶子节点和普通节点。
3.节点
树的最基本组成单元,通常包括当前元素内容和指向下一个元素的引用
4.节点的度
当前节点所包含的子树的个数被称为节点的度
5.树的度
树中节点度数最大的值,我们称之为树的度
6.叶子节点
树中度数为0的节点我们称之为叶子节点
7. 分支节点
树中度数不为0的节点,我们称之为分支节点
8.节点的层次
节点的层次从根开始算起,根的层次为1,其余节点的层次为父节点的层次加1
9.树的深度
树中节点的最大层次被称为树的深度
10.有序树和无序树
如果将树中的节点看成是从左往右的有序的,我们称之为有序树。否则的话我们称之为无序树。
...
好吧,树的基本概念就介绍到这里。下面是具体的java代码的实现了哦。
为了记录树这种数据结构,我们必须记录节点和节点之间的关系。
主要有两种记录树与树之间的关系
1.父节点表示法,每个子节点都记录它所对应的父节点
2.子节点表示法,每个父节点都记录它所对应的所有子节点
下面从代码的角度进行相应的讲解
一、父节点表示法
package com.yonyou.test; import java.util.ArrayList; import java.util.List; import com.yonyou.test.TreeParent.Node; /** * 测试类 * @author 小浩 * @创建日期 2015-3-20 */ public class Test { public static void main(String[] args){ TreeParent<String> tp = new TreeParent<String>("root"); TreeParent.Node<String> root = tp.root(); System.out.println(root); tp.addNode("节点1" , root); System.out.println("此树的深度:" + tp.deep()); tp.addNode("节点2" , root); // 获取根节点的所有子节点 List<Node<String>> nodes = tp.children(root); System.out.println("根节点的第一个子节点:" + nodes.get(0)); // 为根节点的第一个子节点新增一个子节点 tp.addNode("节点3" , nodes.get(0)); System.out.println("此树的深度:" + tp.deep()); } } /** * 父节点表示法,当前子节点记录他所对应的父节点的位置 * @author 小浩 * @创建日期 2015-3-23 * @param <E> */ class TreeParent<E> { //树中能够存储的最大节点的个数 private final int DEFAULT_TREE_SIZE = 100; //树中实际节点对的个数 private int treeSize = 0; //内部类,用于存储相应的节点内容 public static class Node<T> { //保存对应的数据 T data; // 记录其父节点的位置 int parent; public Node() { } public Node(T data) { this.data = data; } public Node(T data , int parent) { this.data = data; this.parent = parent; } public String toString() { return "TreeParent$Node[data=" + data + ", parent=" + parent + "]"; } } // 使用一个Node[]数组来记录该树里的所有节点 private Node<E>[] nodes; // 记录节点数 private int nodeNums; // 以指定根节点创建树 @SuppressWarnings("unchecked") public TreeParent(E data) { treeSize = DEFAULT_TREE_SIZE; nodes = new Node[treeSize]; nodes[0] = new Node<E>(data , -1); nodeNums++; } /** * 以指定根节点、指定treeSize创建树 * @param data * @param treeSize */ @SuppressWarnings("unchecked") public TreeParent(E data ,int treeSize) { this.treeSize = treeSize; nodes = new Node[treeSize]; nodes[0] = new Node<E>(data , -1); nodeNums++; } /** * 为指定节点添加子节点 * @param data * @param parent */ public void addNode(E data , Node parent) { for (int i = 0 ; i < treeSize ; i++) { // 找到数组中第一个为null的元素,该元素保存新节点 if (nodes[i] == null) { //创建新节点,并用指定的数组元素保存它 nodes[i] = new Node<E>(data , pos(parent));; nodeNums++; return; } } throw new RuntimeException("该树已满,无法添加新节点"); } /** * 判断树是否为空。 */ public boolean empty() { // 根节点是否为null return nodes[0] == null; } /** * 返回根节点 * @return */ public Node<E> root() { // 返回根节点 return nodes[0]; } /** * 返回指定节点(非根节点)的父节点。 */ public Node<E> parent(Node node) { // 每个节点的parent记录了其父节点的位置 return nodes[node.parent]; } /** * 返回指定节点(非叶子节点)的所有子节点。 * @param parent * @return */ public List<Node<E>> children(Node parent) { List<Node<E>> list = new ArrayList<Node<E>>(); for (int i = 0 ; i < treeSize ; i++) { // 如果当前节点的父节点的位置等于parent节点的位置 if (nodes[i] != null && nodes[i].parent == pos(parent)) { list.add(nodes[i]); } } return list; } /** * 返回该树的深度。 */ public int deep() { // 用于记录节点的最大深度 int max = 0; for(int i = 0 ; i < treeSize && nodes[i] != null ; i++) { // 初始化本节点的深度 int def = 1; // m记录当前节点的父节点的位置 int m = nodes[i].parent; // 如果其父节点存在 while(m != -1 && nodes[m] != null) { // 向上继续搜索父节点 m = nodes[m].parent; def++; } if(max < def) { max = def; } } // 返回最大深度 return max; } /** * 返回包含指定值的节点。 * @param node * @return */ public int pos(Node node) { for (int i = 0 ; i < treeSize ; i++) { // 找到指定节点 if (nodes[i] == node) { return i; } } return -1; } }
二、子节点表示法
package com.yonyou.test; import java.util.ArrayList; import java.util.List; /** * 测试类 * @author 小浩 * @创建日期 2015-3-20 */ public class Test { public static void main(String[] args){ TreeChild<String> treeChild=new TreeChild<String>("0"); TreeChild.Node<String> root=treeChild.root(); System.out.println("当前树的根节点为:"+root.data); treeChild.addNode("1",root); treeChild.addNode("2",root); treeChild.addNode("3",treeChild.children(root).get(0)); System.out.println("树的深度为:"+treeChild.deep()); } } /** * 子节点表示法,当前子节点记录他所对应的所有子节点的位置 * @author 小浩 * @创建日期 2015-3-23 * @param <E> */ class TreeChild<E> { /** * 静态内部子类链 * @author 小浩 * @创建日期 2015-3-23 */ private static class SonNode { // 记录当前节点的位置 private int pos; private SonNode next; public SonNode(int pos , SonNode next) { this.pos = pos; this.next = next; } } /** * 静态内部类Node,用于存储相关节点的内容和对应子节点的首个链 * @author 小浩 * @创建日期 2015-3-23 * @param <T> */ public static class Node<T> { T data; // 记录第一个子节点 SonNode first; public Node(T data) { this.data = data; this.first = null; } public String toString() { if (first != null) { return "TreeChild$Node[data=" + data + ", first=" + first.pos + "]"; } else { return "TreeChild$Node[data=" + data + ", first=-1]"; } } } //树中能够存储的节点的最大数量 private final int DEFAULT_TREE_SIZE = 100; //树中实际存储的节点个数 private int treeSize = 0; // 使用一个Node[]数组来记录该树里的所有节点 private Node<E>[] nodes; // 记录节点数 private int nodeNums; /** * 以指定根节点创建树 * @param data */ @SuppressWarnings("unchecked") public TreeChild(E data) { treeSize = DEFAULT_TREE_SIZE; nodes = new Node[treeSize]; nodes[0] = new Node<E>(data); nodeNums++; } /** * 以指定根节点、指定treeSize创建树 */ @SuppressWarnings("unchecked") public TreeChild(E data ,int treeSize) { this.treeSize = treeSize; nodes = new Node[treeSize]; nodes[0] = new Node<E>(data); nodeNums++; } /** * 为指定节点添加子节点 * @param data * @param parent */ public void addNode(E data , Node parent) { for (int i = 0 ; i < treeSize ; i++) { // 找到数组中第一个为null的元素,该元素保存新节点 if (nodes[i] == null) { // 创建新节点,并用指定数组元素来保存它 nodes[i] = new Node<E>(data); if (parent.first == null) { parent.first = new SonNode(i , null); } else { SonNode next = parent.first; while (next.next != null) { next = next.next; } next.next = new SonNode(i , null); } nodeNums++; return; } } throw new RuntimeException("该树已满,无法添加新节点"); } /** * 判断树是否为空。 * @return */ public boolean empty() { // 根节点是否为null return nodes[0] == null; } /** * 返回根节点 * @return */ public Node<E> root() { // 返回根节点 return nodes[0]; } /** * 返回指定节点(非叶子节点)的所有子节点。 */ public List<Node<E>> children(Node parent) { List<Node<E>> list = new ArrayList<Node<E>>(); // 获取parent节点的第一个子节点 SonNode next = parent.first; // 沿着孩子链不断搜索下一个孩子节点 while (next != null) { // 添加孩子链中的节点 list.add(nodes[next.pos]); next = next.next; } return list; } /** * 返回指定节点(非叶子节点)的第index个子节点。 * @param parent * @param index * @return */ public Node<E> child(Node<E> parent , int index) { // 获取parent节点的第一个子节点 SonNode next = parent.first; // 沿着孩子链不断搜索下一个孩子节点 for (int i = 0 ; next != null ; i++) { if (index == i) { return nodes[next.pos]; } next = next.next; } return null; } /** * 返回该树的深度。 * @return */ public int deep() { // 获取该树的深度 return deep(root()); } /** * 采用递归的方式方式查找出树的最大深度 * @param root * @return */ private int deep(Node<E> node) { if(node.first==null) return 1; else{ int maxDeep=0; SonNode sonNode=node.first; while(sonNode!=null) { int tempDeep=deep(nodes[sonNode.pos]); if(tempDeep>maxDeep) maxDeep=tempDeep; sonNode=sonNode.next; } return maxDeep+1; } } /** * 返回包含指定值的节点。 * @param node * @return */ public int pos(Node<E> node) { for (int i = 0 ; i < treeSize ; i++) { // 找到指定节点 if (nodes[i] == node) { return i; } } return -1; } }
三、二叉树的讲解
对于普通树而言,由于它们没有特定的规律,所以在现实生活中的应用不如二叉树广泛。
所谓二叉树,指的就是让每棵树中的节点最多有两个子节点,而且它们是严格的区分左子节点和右子节点的。
下面简单说一下二叉树和普通树的区别和联系
1、树中节点的度数是没有限制的,而二叉树中的节点的最大度数是有限制,最大为2.
2、普通树的节点无左右节点之分,但是二叉树是严格区分左右节点的。
什么样的树为满二叉树?
一个深度为k的二叉树,它所包含的节点的个数为2^k-1个节点的话,那么这样的树被称为满二叉树。
什么样的树为完全二叉树呢?
如果一棵二叉树除最后一层外,其余层都是满的。并且最后一层或者是满的,或者仅在右边缺少若干连续的节点,则此二叉树
被称为完全二叉树。
下面简单讲解一下二叉树的常见特性,如果想要了解详细的内容的话,请自己百度...谢谢。
1.二叉树第n层上面节点的个数为2^(n-1)。
2.深度为k的二叉树最多有2^n-1个节点,即我们所说的满二叉树。
3.在任何一棵二叉树上面,如果其叶子节点的度数为n0,度数为2的节点的个数为n2,那么下面的等式是一定成立的。
n0=n2+1;
4.具有n个节点的完全二叉树的深度为log2(n+1);
下面以具体的代码为例讲解二叉树的实现过程
1.二叉树的顺序存储
首先进行一下说明,当使用数组进行存储二叉树的时候可能会产生一定的浪费。
如果该树是完全二叉树的话,那么很好,不会产生任何的空间浪费,但是如果当前二叉树仅仅有右子节点的话
那样的话会产生很大的空间的浪费哦。
package com.yonyou.test; import java.util.ArrayList; import java.util.List; /** * 测试类 * @author 小浩 * @创建日期 2015-3-20 */ public class Test { public static void main(String[] args){ ArrayBinTree<String> binTree =new ArrayBinTree<String>(4, "根"); binTree.add(0 , "第二层右子节点" , false); binTree.add(2 , "第三层右子节点" , false); binTree.add(6 , "第四层右子节点" , false); System.out.println(binTree); } } /** * 子节点表示法,当前子节点记录他所对应的所有子节点的位置 * @author 小浩 * @创建日期 2015-3-23 * @param <E> */ class ArrayBinTree<T> { // 使用数组来记录该树的所有节点 private Object[] datas; // 使用数组的深度 private int DEFAULT_DEEP = 8; // 保存该树的深度 private int deep; //树中实际节点的个数 private int arraySize; /** * 以默认的深度来创建二叉树 */ public ArrayBinTree() { this.deep = DEFAULT_DEEP; this.arraySize = (int)Math.pow(2 , deep) - 1; datas = new Object[arraySize]; } /** * 以指定深度来创建二叉树 * @param deep */ public ArrayBinTree(int deep) { this.deep = deep; this.arraySize = (int)Math.pow(2 , deep) - 1; datas = new Object[arraySize]; } /** * 以指定深度,指定根节点创建二叉树 * @param deep * @param data */ public ArrayBinTree(int deep , T data) { this.deep = deep; this.arraySize = (int)Math.pow(2 , deep) - 1; datas = new Object[arraySize]; datas[0] = data; } /** * 为指定节点添加子节点。 * @param index 需要添加子节点的父节点的索引 * @param data 新子节点的数据 * @param left 是否为左节点 */ public void add(int index , T data , boolean left) { if (datas[index] == null) { throw new RuntimeException(index + "处节点为空,无法添加子节点"); } if (2 * index + 1 >= arraySize) { throw new RuntimeException("树底层的数组已满,树越界异常"); } // 添加左子节点 if (left) { datas[2 * index + 1] = data; } else { datas[2 * index + 2] = data; } } /** * 判断二叉树是否为空。 * @return */ public boolean empty() { // 根据根元素来判断二叉树是否为空 return datas[0] == null; } /** * 返回根节点。 * @return */ @SuppressWarnings("unchecked") public T root() { return (T)datas[0] ; } /** * 返回指定节点(非根节点)的父节点。 * @param index * @return */ @SuppressWarnings("unchecked") public T parent(int index) { return (T)datas[(index - 1) / 2] ; } /** * 返回指定节点(非叶子)的左子节点。 * @param index * @return */ // 当左子节点不存在时返回null。 @SuppressWarnings("unchecked") public T left(int index) { if (2 * index + 1 >= arraySize) { throw new RuntimeException("该节点为叶子节点,无子节点"); } return (T)datas[index * 2 + 1] ; } /** * 返回指定节点(非叶子)的右子节点。 * @param index * @return */ // 当右子节点不存在时返回null。 @SuppressWarnings("unchecked") public T right(int index) { if (2 * index + 1 >= arraySize) { throw new RuntimeException("该节点为叶子节点,无子节点"); } return (T)datas[index * 2 + 2] ; } /** * 返回该二叉树的深度。 * @param index * @return */ public int deep(int index) { return deep; } /** * 返回指定节点的位置。 * @param data * @return */ public int pos(T data) { // 该循环实际上就是按广度遍历来搜索每个节点 for (int i = 0 ; i < arraySize ; i++) { if (datas[i].equals(data)) { return i; } } return -1; } /** * 重写toString方法 */ public String toString() { return java.util.Arrays.toString(datas); } }
2.二叉树的二叉链表存储
package com.yonyou.test; import java.util.ArrayList; import java.util.List; /** * 测试类 * @author 小浩 * @创建日期 2015-3-20 */ public class Test { public static void main(String[] args){ TwoLinkBinTree<String> binTree = new TwoLinkBinTree<String>("根节点"); // 依次添加节点 TwoLinkBinTree.TreeNode tn1 = binTree.addNode(binTree.root() , "第二层左节点" , true); TwoLinkBinTree.TreeNode tn2 = binTree.addNode(binTree.root() , "第二层右节点" ,false ); TwoLinkBinTree.TreeNode tn3 = binTree.addNode(tn2 , "第三层左节点" , true); TwoLinkBinTree.TreeNode tn4 = binTree.addNode(tn2 , "第三层右节点" , false); TwoLinkBinTree.TreeNode tn5 = binTree.addNode(tn3 , "第四层左节点" , true); System.out.println("tn2的左子节点:" + binTree.leftChild(tn2)); System.out.println("tn2的右子节点:" + binTree.rightChild(tn2)); System.out.println(binTree.deep()); } } /** * 二叉树的二叉链表存储法 * @author 小浩 * @创建日期 2015-3-23 * @param <E> */ class TwoLinkBinTree<E> { /** * 存储相应节点的内部类 * @author 小浩 * @创建日期 2015-3-23 */ public static class TreeNode { Object data; TreeNode left; TreeNode right; public TreeNode() { } public TreeNode(Object data) { this.data = data; } public TreeNode(Object data , TreeNode left , TreeNode right) { this.data = data; this.left = left; this.right = right; } } //当前树的根节点 private TreeNode root; // 以默认的构造器来创建二叉树 public TwoLinkBinTree() { this.root = new TreeNode(); } // 以指定根元素来创建二叉树 public TwoLinkBinTree(E data) { this.root = new TreeNode(data); } /** * 为指定节点添加子节点。 * @param index 需要添加子节点的父节点的索引 * @param data 新子节点的数据 * @param isLeft 是否为左节点 * @return 新增的节点 */ public TreeNode addNode(TreeNode parent , E data , boolean isLeft) { if (parent == null) { throw new RuntimeException(parent + "节点为null,无法添加子节点"); } if (isLeft && parent.left != null) { throw new RuntimeException(parent + "节点已有左子节点,无法添加左子节点"); } if (!isLeft && parent.right != null) { throw new RuntimeException(parent + "节点已有右子节点,无法添加右子节点"); } TreeNode newNode = new TreeNode(data); if (isLeft) { // 让父节点的left引用指向新节点 parent.left = newNode; } else { // 让父节点的right引用指向新节点 parent.right = newNode; } return newNode; } /** * 判断二叉树是否为空。 * @return */ public boolean empty() { // 根据根元素来判断二叉树是否为空 return root.data == null; } /** * 返回根节点。 * @return */ public TreeNode root() { if (empty()) { throw new RuntimeException("树为空,无法访问根节点"); } return root; } /** * 返回指定节点(非根节点)的父节点。 * @param node * @return */ public E parent(TreeNode node) { // 对于二叉链表存储法,如果要访问指定节点的父节点必须遍历二叉树 return null; } /** * 返回指定节点(非叶子)的左子节点。当左子节点不存在时返回null * @param parent * @return */ @SuppressWarnings("unchecked") public E leftChild(TreeNode parent) { if (parent == null) { throw new RuntimeException(parent + "节点为null,无法添加子节点"); } return parent.left == null ? null : (E)parent.left.data; } /** * 返回指定节点(非叶子)的右子节点。当右子节点不存在时返回null * @param parent * @return */ @SuppressWarnings("unchecked") public E rightChild(TreeNode parent) { if (parent == null) { throw new RuntimeException(parent + "节点为null,无法添加子节点"); } return parent.right == null ? null : (E)parent.right.data; } /** * 返回该二叉树的深度。 * @return */ public int deep() { // 获取该树的深度 return deep(root); } /** * 这是一个递归方法:每棵子树的深度为其所有子树的最大深度 + 1 * @param node * @return */ private int deep(TreeNode node) { if (node == null) { return 0; } // 没有子树 if (node.left == null && node.right == null) { return 1; } else { int leftDeep = deep(node.left); int rightDeep = deep(node.right); // 记录其所有左、右子树中较大的深度 int max = leftDeep > rightDeep ? leftDeep : rightDeep; // 返回其左右子树中较大的深度 + 1 return max + 1; } } }
3.二叉树的三叉链表存储
package com.yonyou.test; /** * 测试类 * @author 小浩 * @创建日期 2015-3-20 */ public class Test { public static void main(String[] args) { ThreeLinkBinTree<String> binTree = new ThreeLinkBinTree("根节点"); //依次添加节点 ThreeLinkBinTree.TreeNode tn1 = binTree.addNode(binTree.root() , "第二层左节点" , true); ThreeLinkBinTree.TreeNode tn2 = binTree.addNode(binTree.root() , "第二层右节点" ,false ); ThreeLinkBinTree.TreeNode tn3 = binTree.addNode(tn2 , "第三层左节点" , true); ThreeLinkBinTree.TreeNode tn4 = binTree.addNode(tn2 , "第三层右节点" , false); ThreeLinkBinTree.TreeNode tn5 = binTree.addNode(tn3 , "第四层左节点" , true); System.out.println("tn2的父节点:" + binTree.parent(tn2)); System.out.println("tn2的左子节点:" + binTree.leftChild(tn2)); System.out.println("tn2的右子节点:" + binTree.rightChild(tn2)); System.out.println(binTree.deep()); } } /** * 二叉树的二叉链表存储法 * @author 小浩 * @创建日期 2015-3-23 * @param <E> */ class ThreeLinkBinTree<E> { public static class TreeNode { Object data; TreeNode left; TreeNode right; TreeNode parent; public TreeNode() { } public TreeNode(Object data) { this.data = data; } public TreeNode(Object data , TreeNode left , TreeNode right , TreeNode parent) { this.data = data; this.left = left; this.right = right; this.parent = parent; } } private TreeNode root; // 以默认的构造器来创建二叉树 public ThreeLinkBinTree() { this.root = new TreeNode(); } // 以指定根元素来创建二叉树 public ThreeLinkBinTree(E data) { this.root = new TreeNode(data); } /** * 为指定节点添加子节点。 * @param index 需要添加子节点的父节点的索引 * @param data 新子节点的数据 * @param isLeft 是否为左节点 * @return 新增的节点 */ public TreeNode addNode(TreeNode parent , E data , boolean isLeft) { if (parent == null) { throw new RuntimeException(parent + "节点为null,无法添加子节点"); } if (isLeft && parent.left != null) { throw new RuntimeException(parent + "节点已有左子节点,无法添加左子节点"); } if (!isLeft && parent.right != null) { throw new RuntimeException(parent + "节点已有右子节点,无法添加右子节点"); } TreeNode newNode = new TreeNode(data); if (isLeft) { // 让父节点的left引用指向新节点 parent.left = newNode; } else { // 让父节点的right引用指向新节点 parent.right = newNode; } // 让新节点的parent引用到parent节点 newNode.parent = parent; return newNode; } // 判断二叉树是否为空。 public boolean empty() { // 根据根元素来判断二叉树是否为空 return root.data == null; } // 返回根节点。 public TreeNode root() { if (empty()) { throw new RuntimeException("树为空,无法访问根节点"); } return root; } // 返回指定节点(非根节点)的父节点。 @SuppressWarnings("unchecked") public E parent(TreeNode node) { if (node == null) { throw new RuntimeException(node + "节点为null,无法访问其父节点"); } return (E)node.parent.data; } // 返回指定节点(非叶子)的左子节点,当左子节点不存在时返回null @SuppressWarnings("unchecked") public E leftChild(TreeNode parent) { if (parent == null) { throw new RuntimeException(parent + "节点为null,无法添加子节点"); } return parent.left == null ? null : (E)parent.left.data; } // 返回指定节点(非叶子)的右子节点,当右子节点不存在时返回null @SuppressWarnings("unchecked") public E rightChild(TreeNode parent) { if (parent == null) { throw new RuntimeException(parent + "节点为null,无法添加子节点"); } return parent.right == null ? null : (E)parent.right.data; } // 返回该二叉树的深度。 public int deep() { // 获取该树的深度 return deep(root); } // 这是一个递归方法:每棵子树的深度为其所有子树的最大深度 + 1 private int deep(TreeNode node) { if (node == null) { return 0; } // 没有子树 if (node.left == null && node.right == null) { return 1; } else { int leftDeep = deep(node.left); int rightDeep = deep(node.right); // 记录其所有左、右子树中较大的深度 int max = leftDeep > rightDeep ? leftDeep : rightDeep; // 返回其左右子树中较大的深度 + 1 return max + 1; } } }
4.二叉树的几种遍历方法的讲解
如果采用顺序存储来保存二叉树的话,那么遍历此二叉树很简单,直接遍历数组就可以了,但是如果要是采用三叉链表或者
而叉链表的话,那么就会有很多的不同哦。
如果采用链表来存储二叉树的话,那么我们可以有两种遍历二叉树的方法:
1)深度优先遍历
a、先序遍历二叉树(前序遍历二叉树)
b、中序遍历二叉树
c、后序遍历二叉树
2)广度优先遍历,右称为按层遍历。
下面将会从具体的代码进行相关内容的讲解:
a、先序遍历二叉树
// 实现先序遍历 public List<TreeNode> preIterator() { return preIterator(root); } private List<TreeNode> preIterator(TreeNode node) { List<TreeNode> list = new ArrayList<TreeNode>(); // 处理根节点 list.add(node); // 递归处理左子树 if (node.left != null) { list.addAll(preIterator(node.left)); } // 递归处理右子树 if (node.right != null) { list.addAll(preIterator(node.right)); } return list; }
b、中序遍历二叉树
// 实现中序遍历 public List<TreeNode> inIterator() { return inIterator(root); } private List<TreeNode> inIterator(TreeNode node) { List<TreeNode> list = new ArrayList<TreeNode>(); // 递归处理左子树 if (node.left != null) { list.addAll(inIterator(node.left)); } // 处理根节点 list.add(node); // 递归处理右子树 if (node.right != null) { list.addAll(inIterator(node.right)); } return list; } public List<TreeNode> postIterator() { return postIterator(root); }
c、后序遍历二叉树
// 实现后序遍历 private List<TreeNode> postIterator(TreeNode node) { List<TreeNode> list = new ArrayList<TreeNode>(); // 递归处理左子树 if (node.left != null) { list.addAll(postIterator(node.left)); } // 递归处理右子树 if (node.right != null) { list.addAll(postIterator(node.right)); } // 处理根节点 list.add(node); return list; }
d、广度优先遍历二叉树
// 广度优先遍历 public List<TreeNode> breadthFirst() { Queue<TreeNode> queue = new ArrayDeque<TreeNode>(); List<TreeNode> list = new ArrayList<TreeNode>(); if( root != null) { // 将根元素加入“队列” queue.offer(root); } while(!queue.isEmpty()) { // 将该队列的“头部”的元素添加到List中 list.add(queue.peek()); // 将该队列的“头部”的元素移出队列 TreeNode p = queue.poll(); // 如果左子节点不为null,将它加入“队列” if(p.left != null) { queue.offer(p.left); } // 如果右子节点不为null,将它加入“队列” if(p.right != null) { queue.offer(p.right); } } return list; }
好吧,由于篇幅的限制,今天先到这里,下一篇我们将要继续探讨树和二叉树的相关内容。
下一篇的地址为: