java算法之二叉树排序

对于树(ADT)形结构,元素的排序不是重点,如果需要排序,一般使用链表、栈、队列等数据结构。

算法中常用二叉树,对于二叉树排序这里先不介绍,给个传送门https://zhuanlan.zhihu.com/p/25623301。

在这里讲一下二叉树的遍历。

二叉树的遍历按当前节点分为三类:

1.前序遍历DLR  D是当前节点 L在D左边 R在D右边 (这其中LR是可以交换的,因为正常是六种遍历)

2.中序遍历LDR

3.后序遍历LRD

还有一种遍历方法不需要依赖上述顺序,即层续遍历,也就是按照层级一层一层的遍历

1.前序遍历DLR

步骤如下:

    1)访问根节点

    2)按照遍历方式遍历左子树

    3)遍历右子树

代码如下: 为了方便直接写中文名的方法了哈~.~

private static void 前序遍历(BinaryTreeNode a) {
// TODO Auto-generated method stub
if(a!=null){
System.out.println(a.getData());
前序遍历(a.getLeft());
前序遍历(a.getRight());
}

}

    从方法中可以看出,应用了递归方法不断的寻找每个节点的左子树和右子树。

那如果正常考虑来遍历呢?请看如下

private static void 非递归前序遍历(BinaryTreeNode a) {
// TODO Auto-generated method stub
if(a == null);
Stack<BinaryTreeNode> S = new Stack<BinaryTreeNode>();
while(true){
while(a != null){
System.out.println(a.getData());
S.push(a);
a = a.getLeft();
}
if(S.isEmpty()){ //这里要用到isEmpty函数而非S == NULL
break;
}
a = S.pop();
a = a.getRight();
}
}

以上代码是非递归版的前序遍历,应用了栈的思想,把每个具有左子树的节点压入到栈中, 遍历之后取出节点 找到其右子树。这样有人会问,那么如果右子树节点包含了左子树那么遍历时是否会忽略呢,答案是:不会 因为在重新寻找右子树节点的时候没有重新定义变量,所以右子树的做节点还是会接着进行遍历的。

2.中序遍历 LDR

顾名思义,还是先遍历左子树在遍历当前节点,然后遍历右子树。代码如下:

private static void 递归中序遍历(BinaryTreeNode a) {
// TODO Auto-generated method stub
if(a==null);
else{
递归中序遍历(a.getLeft());
System.out.println(a.getData());
递归中序遍历(a.getRight());
}

}

依旧,递归也是最好理解且最简单的 主函数如下:

              public static void main(String[] args) {

BinaryTreeNode A = new BinaryTreeNode();
BinaryTreeNode B = new BinaryTreeNode();
BinaryTreeNode C = new BinaryTreeNode();
BinaryTreeNode D = new BinaryTreeNode();
A.setData(5);
B.setData(6);
C.setData(7);
D.setData(8);
A.setLeft(B);
B.setRight(C);
C.setLeft(D);
/*前序遍历(A);
非递归前序遍历(A);*/
递归中序遍历(A);

            }

运行结果是:6 8 7 5 大家可以仔细思考,程序在中序递归运行时的具体过程。

下面给出非递归中续遍历的例程

private static void 非递归中序遍历(BinaryTreeNode a) {
// TODO Auto-generated method stub
if(a == null);
else{
Stack<BinaryTreeNode> S = new Stack<BinaryTreeNode>();
while(true){
while(a!=null){
a = a.getLeft();
S.push(a);
}
if(S.isEmpty()){
break;
}
S.pop();
System.out.println(a.getData());
a = a.getRight();
}
}

}

可以看出,在非递归中,是否出栈和进栈时输出数据可判断是什么遍历。

3.后续遍历

递归方案这里就不赘述啦,相信小伙伴们也已经看懂了,这里详细说一下后续遍历的非递归版本。

在非递归中前序和中序都很好做,但后续要考虑如何最后输出当前节点,其具体代码如下

private static void 非递归后序遍历(BinaryTreeNode a) {
// TODO Auto-generated method stub
Stack<BinaryTreeNode> S = new Stack<BinaryTreeNode>();
while(true){
if(a!=null){
S.push(a);
a = a.getLeft();
}else{
if(S.isEmpty()){
break;
}else{
if(S.get(0).getRight() == null){
a = S.pop();
System.out.println(a.getData());
if(a == S.get(0).getRight()){
System.out.println(S.get(0).getData());
S.pop();
}
}
if(!S.isEmpty()){
a = S.get(0).getRight();
}else{
a = null;
}
}
}
}
}

猜你喜欢

转载自blog.csdn.net/qq_36186068/article/details/81050360