从这里开始将要进行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;
}
、广度优先遍历二叉树
// 广度优先遍历
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;
}
好吧,由于篇幅的限制,今天先到这里,下一篇我们将要继续探讨树和二叉树的相关内容。