二叉树(Binary tree)是树形结构的一个重要类型。
二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。
一、二叉树类定义
public class TreeNode {
//当前节点
private Integer value;
//左子树
private TreeNode left;
//右子树
private TreeNode right;
public TreeNode(Integer value, TreeNode left, TreeNode right) {
this.value = value;
this.left = left;
this.right = right;
}
public TreeNode(){
}
/**此处省略get和set方法**/
}
二、二叉排序树
二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。是数据结构中的一类。在一般情况下,查询效率比链表结构要高。
根据数组创建二叉排序树:
//创建二叉排序树
public TreeNode create(int[] arr){
TreeNode treeNode = new TreeNode();
for(int i:arr){
treeNode.insert(treeNode,i);
}
return treeNode;
}
//向二叉树插入数据
public void insert(TreeNode treeNode,int value){
if(treeNode.getValue()==null){
treeNode.setValue(value);
}
//插入左子树
if(treeNode.getValue()>value){
if(treeNode.getLeft()==null){
treeNode.setLeft(new TreeNode(value,null,null));
}else{
insert(treeNode.getLeft(),value);
}
}
//插入右子树
if(treeNode.getValue()<value){
if(treeNode.getRight()==null){
treeNode.setRight(new TreeNode(value,null,null));
}else{
insert(treeNode.getRight(),value);
}
}
}
三、实现二叉树遍历
以下面的二叉树为例:
遍历顺序:
先序遍历:根节点→左子树→右子树;
中序遍历:左子树→根节点→右子树;
后序遍历:左子树→右子树→根节点;
遍历结果:
先序遍历:A,B,D,C,E,G,F;
中序遍历:B,D,A,E,G,C,F;
后序遍历:D,B,G,E,F,C,A;
3.1 递归实现
3.1.1 先序遍历(前序遍历)
//先序遍历
public void fristForeach(TreeNode treeNode){
if(treeNode!=null){
System.out.println(treeNode.getValue());
fristForeach(treeNode.getLeft());
fristForeach(treeNode.getRight());
}
}
3.1.2 中序遍历
//中序遍历
public void midForeach(TreeNode treeNode){
if(treeNode!=null){
midForeach(treeNode.getLeft());
System.out.println(treeNode.getValue());
midForeach(treeNode.getRight());
}
}
3.1.3 后序遍历
//后序遍历
public void lastForeach(TreeNode treeNode){
if(treeNode!=null){
lastForeach(treeNode.getLeft());
lastForeach(treeNode.getRight());
System.out.println(treeNode.getValue());
}
}
3.2 辅助栈实现
3.2.1 先序遍历
//非递归式实现先序遍历
public void fristIterateForeach(TreeNode treeNode){
TreeNode t = treeNode;
//使用栈存储根节点
Stack<TreeNode> treeNodeStack = new Stack<>();
while(t!=null||treeNodeStack.size()>0){
//当前节点不为空时
if(t!=null){
//打印根节点
System.out.println(t.getValue());
//存储当前节点
treeNodeStack.push(t);
//访问左子树
t =t.getLeft();
}else{
//获取父节点
t= treeNodeStack.pop();
//获取父节点的右子树
t = t.getRight();
}
}
}
3.2.2 中序遍历
//非递归式实现中序遍历
public void midIterateForeach(TreeNode treeNode){
TreeNode t = treeNode;
//使用栈存储根节点
Stack<TreeNode> treeNodeStack = new Stack<>();
while(t!=null||treeNodeStack.size()>0){
//当前节点不为空时
if(t!=null){
//存储当前节点
treeNodeStack.push(t);
//访问左子树
t =t.getLeft();
}else{
//获取父节点
t= treeNodeStack.pop();
//打印根节点
System.out.print(t.getValue()+" ");
//获取父节点的右子树
t = t.getRight();
}
}
}
3.2.3 后序遍历
后序遍历的顺序为为:左→右→中,而前序遍历为:中→左→右,其实可以理解为对前序遍历调整为:中→右→左,然后进行反转即可实现后序遍历
//非递归式实现后序遍历
public void lastIterateForeach(TreeNode treeNode){
//使用链表反向存储节点
LinkedList<Integer> linkedList = new LinkedList<>();
TreeNode t = treeNode;
//使用栈存储根节点
Stack<TreeNode> treeNodeStack = new Stack<>();
while(t!=null||treeNodeStack.size()>0){
//当前节点不为空时
if(t!=null){
//打印根节点
linkedList.add(0,t.getValue());
//存储当前节点
treeNodeStack.push(t);
//访问左子树
t =t.getRight();
}else{
//获取父节点
t= treeNodeStack.pop();
//获取父节点的右子树
t = t.getLeft();
}
}
for(Integer i :linkedList){
System.out.println(i);
}
}
四、 二叉树高度
public int height(TreeNode treeNode){
if(treeNode==null){
return 0;
}
int leftHeight = height(treeNode.getLeft());
int rightHeight = height(treeNode.getRight());
if(leftHeight>rightHeight)
return (leftHeight+1);
else
return (rightHeight+1);
}
五、叶子节点个数
public int leafCount(TreeNode treeNode){
int count=0;
Stack<TreeNode> treeNodeStack = new Stack<>();
treeNodeStack.push(treeNode);
while(treeNodeStack.size()>0){
TreeNode node = treeNodeStack.pop();
if(node.getRight()==null&&node.getLeft()==null){
count++;
}
if(node.getLeft()!=null){
treeNodeStack.push(node.getLeft());
}
if(node.getRight()!=null){
treeNodeStack.push(node.getRight());
}
}
return count;
}