一、 一般二叉树的实现
这里的一般二叉树指的是没有任何特殊要求的二叉树。
1. 二叉树的建立
步骤1:设计二叉树类的结点,包括左右结点和卫星数据
public class BinaryTreeNode<T> {
private BinaryTreeNode<T> leftChild,rightChild;
private T data;
public BinaryTreeNode() {
// TODO 自动生成的构造函数存根
leftChild=rightChild=null;
}
public BinaryTreeNode(T data) {
// TODO 自动生成的构造函数存根
leftChild=rightChild=null;
this.data=data;
}
public T getData() {
return data;
}
public BinaryTreeNode<T> getLeftChild() {
return leftChild;
}
public BinaryTreeNode<T> getRightChild() {
return rightChild;
}
public void setLeftChild(BinaryTreeNode<T> leftChild) {
this.leftChild = leftChild;
}
public void setRightChild(BinaryTreeNode<T> rightChild) {
this.rightChild = rightChild;
}
}
步骤2:设计最简单的二叉树类
public class BinaryTree<T> {
BinaryTreeNode<T> root;
public BinaryTree(BinaryTreeNode<T> root) {
// TODO 自动生成的构造函数存根
this.root = root;
}
}
步骤3:建立二叉树
public class BinaryTreeTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO 自动生成的方法存根
BinaryTreeNode<String> a = new BinaryTreeNode<String>("A");
BinaryTreeNode<String> b = new BinaryTreeNode<String>("B");
BinaryTreeNode<String> c = new BinaryTreeNode<String>("C");
BinaryTreeNode<String> d = new BinaryTreeNode<String>("D");
BinaryTreeNode<String> e = new BinaryTreeNode<String>("E");
BinaryTreeNode<String> f = new BinaryTreeNode<String>("F");
a.setLeftChild(b);
a.setRightChild(c);
b.setLeftChild(d);
b.setRightChild(e);
c.setLeftChild(f);
BinaryTree<String> binaryTree=new BinaryTree<>(a);
}
}
binaryTree即为一颗这样的二叉树。但是没有任何处理它的函数,包括前序、后续、中序的输出。下面就这个二叉树来讨论这些函数。
2. 二叉树的遍历
1) 分层遍历(广度优先)
参考:http://www.cnblogs.com/miloyip/archive/2010/05/12/binary_tree_traversal.html
《编程之美》给出的方案
/* 树的广度优先搜索(分层输出)*/
public void PrintNodeByLevel () {
ArrayList<BinaryTreeNode<T>> list=new ArrayList<>();
if (root==null) {
return;
}
list.add(root);
int cur=0;
while (cur<list.size()) {
int lastofCurrentLevel=list.size();
while (cur<lastofCurrentLevel) {
BinaryTreeNode<T> tempNode=list.get(cur);
System.out.print(tempNode.getData());
if (tempNode.getLeftChild()!=null) {
list.add(tempNode.getLeftChild());
}
if (tempNode.getRightChild()!=null) {
list.add(tempNode.getRightChild());
}
cur++;
}
System.out.println();
}
}
算法解释:使用辅助队列list,cur为游标,last为list的长度。外层循环是控制level的,内层循环是某一个level的内部遍历。
2) 前序遍历
方案一:递归
/*☆较简单——前序遍历递归过程 */
private void recursePreOrder(BinaryTreeNode<T> root) {
if (root == null)
return;
System.out.print(root.getData());
if (root.getLeftChild() != null)
recursePreOrder(root.getLeftChild());
if (root.getRightChild() != null)
recursePreOrder(root.getRightChild());
}
方案二:辅助的
stack
的方式
(《算法导论》
248
页
10.4-3
)
/* 较简单——使用1个辅助stack方式进行前序遍历 */
private void PreOrderUsingStack(BinaryTreeNode<T> root) {
BinaryTreeNode<T> temp=root;
Stack<BinaryTreeNode<T>> stack=new Stack<>();
while (!stack.isEmpty()||temp!=null) {
if (temp!=null) {
System.out.print(temp.getData());
stack.push(temp);
temp=temp.getLeftChild();
}else {
temp=stack.pop();
temp=temp.getRightChild();
}
}
}
3) 中序遍历
思路:《算法导论》288页
/* ☆较简单——中遍历递归过程 */
private void recurseInOrder(BinaryTreeNode<T> root) {
if (root == null)
return;
if (root.getLeftChild() != null)
recurseInOrder(root.getLeftChild());
System.out.print(root.getData());
if (root.getRightChild() != null)
recurseInOrder(root.getRightChild());
}
4) 后序遍历
参考:http://hi.baidu.com/8qianyun/item/bf61f3dc390a7df493a97434
关键点:前序遍历如果的法则如果改成先遍历右边再遍历左边,将这种算法命名为“left前序遍历”算法。则“left前序遍历”结果为:acfbed。“left前序遍历”结果倒序即为后续遍历:debfca
思路:使用1个辅助stack的方式实现“left前序遍历”算法,用另一个辅助stack进行倒序输出。
/* 较复杂——使用2个辅助stack方式进行后序遍历 */
public void PostOrderUsingStack() {
BinaryTreeNode<T> temp=root;
Stack<BinaryTreeNode<T>> stack=new Stack<>();
Stack<BinaryTreeNode<T>> outPutStack=new Stack<>();
while (!stack.isEmpty()||temp!=null) {
if (temp!=null) {
stack.push(temp);
outPutStack.push(temp);
temp=temp.getRightChild();
}else {
temp=stack.pop();
temp=temp.getLeftChild();
}
}
System.out.print("\n使用2个辅助stack进行后续输出:");
while (!outPutStack.isEmpty()) {
System.out.print(outPutStack.pop().getData());
}
3. 其他常用处理函数
1) 求二叉树中的节点个数
思路:递归的方案,二叉树节点个数 = 左子树节点个数 + 右子树节点个数 + 1
private int getNodeNumber(BinaryTreeNode<T> root) {
if (root==null) {
return 0;
}else {
return 1+getNodeNumber(root.getLeftChild())+getNodeNumber(root.getRightChild());
}
}
public int getNodeNumber() {
return getNodeNumber(root);
}
2) 求二叉树深度
思路:二叉树的深度 = max(左子树深度,右子树深度) + 1
/* 获得树的高度,递归过程 */
private int getTreeDeep(BinaryTreeNode<T> root) {
if (root == null) {
return 0;
}
if (root.getLeftChild() == null && root.getRightChild() == null) {
return 1;
}
return 1 + Math.max(getTreeDeep(root.getLeftChild()),
getTreeDeep(root.getRightChild()));
}
public int getFianlTreeDeep() {
return getTreeDeep(root);
}
3) 二叉树第K层的节点个数
思路:如果二叉树不为空且k>1,返回左子树中k-1层的节点个数与右子树k-1层节点个数之和。当然也可以用广度优先算法来计算第k层的节点个数。
/* 递归方案获取第K层的节点个数*/
public int getNumberofKthLevel(BinaryTreeNode<T> node,int k) {
if (node==null||k<1) {
return 0;
}
if (k==1) {
return 1;
}
int leftNumber=getNumberofKthLevel(node.getLeftChild(),k-1);
int rightNumber=getNumberofKthLevel(node.getRightChild(), k-1);
return leftNumber+rightNumber;
}
public int getNumberofKthLevel(int k) {
return getNumberofKthLevel(root, k);
}
4) 获取叶子节点个数
思路:如果二叉树不为空,且左右子树不同时为空,返回左子树中叶子节点个数加上右子树中叶子节点个数
/* 递归方案获取叶子节点个数*/
public int getLeafNumber(BinaryTreeNode<T> node) {
if (node==null) {
return 0;
}
if (node.getRightChild()==null&&node.getLeftChild()==null) {
return 1;
}
int leftNumber=getLeafNumber(node.getLeftChild());
int rightNumber=getLeafNumber(node.getRightChild());
return leftNumber+rightNumber;
}
public int getLeafNumber() {
return getLeafNumber(root);
}
5) 判断两颗二叉树是否结构相同
思路:如果两棵二叉树都不为空,如果对应的左子树和右子树都同构返回真,其他返回假
/* 递归方案比较两个二叉树是否结构相同*/
public static boolean isSameOfTreeStucture(BinaryTreeNode<String> tree1Root,BinaryTreeNode<String> tree2Root) {
if (tree1Root==null&&tree2Root==null) {
return true;
}else if (tree1Root==null||tree2Root==null) {
return false;
}
boolean leftFlag=isSameOfTreeStucture(tree1Root.getLeftChild(), tree2Root.getLeftChild());
boolean rightFlag=isSameOfTreeStucture(tree1Root.getRightChild(), tree2Root.getRightChild());
return leftFlag&&rightFlag;
}
}
6) 求二叉树的镜像
思路:如果二叉树不为空,求左子树和右子树的镜像,然后交换左子树和右子树
/* 递归方案进行镜像反转*/
public static BinaryTreeNode<String> getMirrorTree(BinaryTreeNode<String> node) {
if (node==null) {
return null;
}
BinaryTreeNode<String> leftMirror=getMirrorTree(node.getLeftChild());
BinaryTreeNode<String> rightMirror=getMirrorTree(node.getRightChild());
node.setLeftChild(rightMirror);
node.setRightChild(leftMirror);
return node;
}
****************************************************************************************************************************************************************************************
【百度的面试题】输出二叉树第 m 层的第 k 个节点值(m, k 均从 0 开始计数)
/* 树的广度优先搜索(分层输出)*/
public void PrintNodeByLevelAndNumber (int k,int m) {
ArrayList<BinaryTreeNode<T>> list=new ArrayList<>();
if (root==null) {
return;
}
list.add(root);
int cur=0;
int level=0;
int pointer=0;
while (cur<list.size()) {
int lastofCurrentLevel=list.size();
level++;
while (cur<lastofCurrentLevel) {
BinaryTreeNode<T> tempNode=list.get(cur);
if (level==k) {
pointer++;
}
if (level==k&&pointer==m) {
System.out.print(tempNode.getData());
}
if (tempNode.getLeftChild()!=null) {
list.add(tempNode.getLeftChild());
}
if (tempNode.getRightChild()!=null) {
list.add(tempNode.getRightChild());
}
cur++;
}
System.out.println();
}
}