二叉树(一)二叉树的递归与非递归遍历;二叉树的后继节点

一.二叉树的递归遍历与非递归遍历

先序遍历:根节点,左节点,右节点。

中序遍历:左根右

后序遍历:左右根

二叉树:

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));
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值