一.二叉树的递归遍历与非递归遍历
先序遍历:根节点,左节点,右节点。
中序遍历:左根右
后序遍历:左右根
二叉树:
public static class Node {
int value;
Node left;
Node right;
Node(int data) {
this.value = data;
}
}
1.1递归方式:三种遍历
// 先序遍历递归版本
public static void printPreTree0(Node head) {
if (head == null)
return;
System.out.print(head.value + " ");
printPreTree0(head.left);
printPreTree0(head.right);
}
// 中序
public static void printMidTree0(Node head) {
if (head == null)
return;
printMidTree0(head.left);
System.out.print(head.value + " ");
printMidTree0(head.right);
}
// 后序
public static void printPosTree0(Node head) {
if (head == null)
return;
printPosTree0(head.left);
printPosTree0(head.right);
System.out.print(head.value + " ");
}
1.2非递归方式:
先序(根左右)
思路: 找一个栈,先把根节点放入,然后弹出栈顶a输出a,把a的 右 左 节点压入栈,然后再弹出栈顶(刚刚压入的左节点),再压入刚刚弹出节点的 右 左 节点,直到栈为空
public static void printPreTree1(Node head) {
if (head == null)
return;
Stack<Node> a = new Stack<Node>();
a.push(head);
Node help = null;
while (!a.isEmpty()) {
help = a.pop();
System.out.print(help.value + " ");
if (help.right != null)
a.push(help.right);
if (help.left != null)
a.push(help.left);
}
}
中序 左中右
1.递归的本质也可以看作是压栈。
2.借助栈要考虑:压栈的顺序(也就是处理 子问题 的顺序可以看作在栈顶弹出一个元素便是处理一个子问题)
/*
* 3.显然中序遍历的过程是,先从最左边开始然后是其根节点,然后是右边,对于右边,又重复上述过程,右子树结束后回到刚刚节点的根节点,然后又开始遍历右子树)
* 所以可以把对右子树的遍历当作子过程 把那些根节点当作压栈的顺序(),每出一次栈,便是对子问题的解决
* 4.所以当一个根节点放入函数时,不停的对他进行左节点层层压入栈,直到左节点为空 当从栈中拿出一个元素时,将其右节点重复上述过程
* 整过过程在while函数中进行(几乎所有递归都可以用循环完成 递归过程也是一个压栈过程)
*/
public static void printMidTree1(Node head) {
if (head == null)
return;
Stack<Node> stack = new Stack<Node>();
while (!stack.isEmpty()||head!=null) {
while (head != null) {
stack.push(head);
head = head.left;
}
head = stack.pop();
System.out.print(head.value+" ");
head = head.right;
}
}
后序 左右中
在先序遍历中压栈顺序是中右左 代码完成后得到的输出顺序是 中 左 右,
在后序遍历中我们可以把 压栈顺序改为 中左右 所以得到的输出顺序应该为中 右 左 然后此输出顺序我们并不采取输出代码,而是压入另一个栈StackB中,所以从StackB得到的输出顺序是左右中:代码实现
// 非递归后序
public static void printPosTree1(Node head) {
if(head==null) return ;
Stack<Node>a=new Stack<>();
Stack<Node>b=new Stack<>();
a.push(head);
Node help=null;
while(!a.isEmpty()) {
help=a.pop();
//System.out.println(help.value);
b.push(help);
if(help.left!=null)
a.push(help.left);
if(help.right!=null)
a.push(help.right);
}
while(!b.isEmpty()) {
System.out.print(b.pop().value+" ");
}
}
后序2:(记录一下另一种方式 ,可以忽略)
public static void posOrderUnRecur2(Node h) {
System.out.print("pos-order: ");
if (h != null) {
Stack<Node> stack = new Stack<Node>();
stack.push(h);
Node c = null;
while (!stack.isEmpty()) {
c = stack.peek();
if (c.left != null && h != c.left && h != c.right) {
stack.push(c.left);
} else if (c.right != null && h != c.right) {
stack.push(c.right);
} else {
System.out.print(stack.pop().value + " ");
h = c;
}
}
}
System.out.println();
}
完整测试代码:(可以忽略)
package BinaryTree;
import java.util.Stack;
public class threePrintTree {
public static class Node {
int value;
Node left;
Node right;
Node(int data) {
this.value = data;
}
}
// 先序遍历递归版本
public static void printPreTree0(Node head) {
if (head == null)
return;
System.out.print(head.value + " ");
printPreTree0(head.left);
printPreTree0(head.right);
}
// 中序
public static void printMidTree0(Node head) {
if (head == null)
return;
printMidTree0(head.left);
System.out.print(head.value + " ");
printMidTree0(head.right);
}
// 后序
public static void printPosTree0(Node head) {
if (head == null)
return;
printPosTree0(head.left);
printPosTree0(head.right);
System.out.print(head.value + " ");
}
// 先序非递归
// 找一个栈,先把根节点放入,然后弹出栈顶a输出a,把a的 右 左 节点压入栈,然后再弹出栈顶(刚刚压入的左节点),再压入刚刚弹出节点的 右 左 节点,直到栈为空
public static void printPreTree1(Node head) {
if (head == null)
return;
Stack<Node> a = new Stack<Node>();
a.push(head);
Node help = null;
while (!a.isEmpty()) {
help = a.pop();
System.out.print(help.value + " ");
if (help.right != null)
a.push(help.right);
if (help.left != null)
a.push(help.left);
}
}
// 中序非递归 左中右
// 借助栈要考虑:压栈的顺序(也就是处理 子问题 的顺序可以看作在栈顶弹出一个元素便是处理一个子问题)
/*
* 显然中序遍历的过程是,先从最左边开始然后是其根节点,然后是右边,对于右边,又重复上述过程,右子树结束后回到刚刚节点的根节点,然后又开始遍历右子树)
* 所以可以把对右子树的遍历当作子过程 把那些根节点当作压栈的顺序(),每出一次栈,便是对子问题的解决
* 所以当一个根节点放入函数时,不停的对他进行左节点层层压入栈,直到左节点为空 当从栈中拿出一个元素时,将其右节点重复上述过程
* 整过过程在while函数中进行(几乎所有递归都可以用循环完成 递归过程也是一个压栈过程)
*/
public static void printMidTree1(Node head) {
if (head == null)
return;
Stack<Node> stack = new Stack<Node>();
while (!stack.isEmpty()||head!=null) {
while (head != null) {
stack.push(head);
head = head.left;
}
head = stack.pop();
System.out.print(head.value+" ");
head = head.right;
}
}
// 非递归后序
public static void printPosTree1(Node head) {
if(head==null) return ;
Stack<Node>a=new Stack<>();
Stack<Node>b=new Stack<>();
a.push(head);
Node help=null;
while(!a.isEmpty()) {
help=a.pop();
//System.out.println(help.value);
b.push(help);
if(help.left!=null)
a.push(help.left);
if(help.right!=null)
a.push(help.right);
}
while(!b.isEmpty()) {
System.out.print(b.pop().value+" ");
}
}
public static void main(String[] args) {
Node head = new Node(5);
head.left = new Node(3);
head.right = new Node(8);
head.left.left = new Node(2);
head.left.right = new Node(4);
head.left.left.left = new Node(1);
head.right.left = new Node(7);
head.right.left.left = new Node(6);
head.right.right = new Node(10);
head.right.right.left = new Node(9);
head.right.right.right = new Node(11);
// recursive
System.out.println("==============recursive==============");
System.out.print("pre-order: ");
printPreTree1(head);
System.out.println();
System.out.print("in-order: ");
printMidTree0(head);
System.out.println();
printMidTree1(head);
System.out.println();
System.out.print("pos-order: ");
printPosTree0(head);
System.out.println();
printPosTree1(head);
System.out.println();
}
}
二.二叉树的后继节点
后继节点:在中序遍历中,节点的下一个节点便是其后继节点
前驱结点:同理。在中序遍历中,节点的上一个节点便是其前驱结点
2.1 怎么找到后继节点
当前节点有右节点:以右孩子为起点,依次向左子遍历 ,直到无左子 停 返回这个无左子的节点
当前节点无右节点:以当前节点为起点,依次向上层遍历,直到节点找到一个等节点a,a 的父节点的左孩子是a节点,返回a的
父节点。如果直到a的父节点已经是空,则当前节点无后继,返回空
public static Node getNextNode(Node head) {
if (head==null) return null;
//有右孩子,以右孩子为根节点依次向左遍历到无左子,停
if(head.right!=null) return getleft(head.right);
//没有右孩子,则依次向上找父节点,直到找到一个父节点,自己是他的左孩子,如果到顶点也没有找到,则该节点没有后继
else {
return getparent(head);
}
}
private static Node getparent(Node head) {
while(head.parent!=null) {
if(head==head.parent.left)
{
return head.parent;}
head=head.parent;
}
return null;
}
private static Node getleft(Node head) {
while(head.left!=null) {
head=head.left;
}
return head;
}
完整测试代码:(可忽略)
package BinaryTree;
public class getSuccessNode {
public static class Node{
int value;
Node left;
Node right;
Node parent;
public Node(int data) {
this.value=data;
}
}
public static Node getNextNode(Node head) {
if (head==null) return null;
//有右孩子,以右孩子为根节点依次向左遍历到无左子,停
if(head.right!=null) return getleft(head.right);
//没有右孩子,则依次向上找父节点,直到找到一个父节点,自己是他的左孩子,如果到顶点也没有找到,则该节点没有后继
else {
return getparent(head);
}
}
private static Node getparent(Node head) {
while(head.parent!=null) {
if(head==head.parent.left)
{
return head.parent;}
head=head.parent;
}
return null;
}
private static Node getleft(Node head) {
while(head.left!=null) {
head=head.left;
}
return head;
}
public static void main(String[] args) {
Node head = new Node(6);
head.parent = null;
head.left = new Node(3);
head.left.parent = head;
head.left.left = new Node(1);
head.left.left.parent = head.left;
head.left.left.right = new Node(2);
head.left.left.right.parent = head.left.left;
head.left.right = new Node(4);
head.left.right.parent = head.left;
head.left.right.right = new Node(5);
head.left.right.right.parent = head.left.right;
head.right = new Node(9);
head.right.parent = head;
head.right.left = new Node(8);
head.right.left.parent = head.right;
head.right.left.left = new Node(7);
head.right.left.left.parent = head.right.left;
head.right.right = new Node(10);
head.right.right.parent = head.right;
Node test = head.left.left;
System.out.println(test.value + " next: " + getNextNode(test).value);
test = head.left.left.right;
System.out.println(test.value + " next: " + getNextNode(test).value);
test = head.left;
System.out.println(test.value + " next: " + getNextNode(test).value);
test = head.left.right;
System.out.println(test.value + " next: " + getNextNode(test).value);
test = head.left.right.right;
System.out.println(test.value + " next: " + getNextNode(test).value);
test = head;
System.out.println(test.value + " next: " + getNextNode(test).value);
test = head.right.left.left;
System.out.println(test.parent.value);
//if(test.parent.left==test) System.out.println("yes");
System.out.println(test.value + " next: " + getNextNode(test).value);
test = head.right.left;
System.out.println(test.value + " next: " + getNextNode(test).value);
test = head.right;
System.out.println(test.value + " next: " + getNextNode(test).value);
test = head.right.right; // 10's next is null
System.out.println(test.value + " next: " + getNextNode(test));
}
}