二叉树的整理

1.二叉树的创建

二叉树的创建,这里使用的"#"作为停止符创建的时候也是前序的方式创建的

	public void createBiTree()
	{
		root = createBiTree(root);
	}

	private Node createBiTree(Node x)
	{
		Scanner in = new Scanner(System.in);
		String str = in.next();
		if(str.equals("#"))
			return null;
		else
		{
			x = new Node(str);
			x.left = createBiTree(x.left);
			x.right = createBiTree(x.right);
		}
		return x;           //这行代码好好理解
	}

二叉树的创建和二叉排序树的创建,在C语言中因为有指针,所以送入参数的是结点的左右子树的地址,而Java中没有指针,所以采用的是添加一个结点后,将该结点返回的方式,返回给它上一级结点的左右子树。类似的情况,还发生在在没有头结点的链表中采用头插法,此时将头结点复制给形参,对形参操作后,头结点已经被后移动了一位,此时需要重新赋值头结点

这里使用的Scanner输入的,其实使用BufferedReader也是可以的

代码实现:

	private Node createBiTree(Node x){
		//Scanner in = new Scanner(System.in);
		BufferedReader bis = new BufferedReader(new InputStreamReader(System.in));
		try{
			String str = bis.readLine();
		//String str = in.nextLine();
		if(str.equals("#")){
			return null;
		}else{
			x = new Node(str);
			x.left = createBiTree(x.left);
			x.right = createBiTree(x.right);
		}
		}catch(Exception e){	
		}
		return x;
	}

Sanner和BufferedReader的区别:https://blog.csdn.net/zengxiantao1994/article/details/78056243

这个createBiTree函数中的返回return x,要理解,创建完二叉树后,还会返回根结点

2.二叉树的前序、中序、后续遍历

1)前序遍历的两种方式:

前序递归方式:

	public void preOrder(Node x)
	{
		if(x==null)
			return;
		System.out.print(x.str+" ");
		preOrder(x.left);
		preOrder(x.right);
	}
前序非递归方式:
 
 
	public void preOrder(Node root){
		Stack<Node> stack = new Stack<>();
		while(root!=null||!stack.isEmpty()){
			while(root!=null){		//将左边的都遍历完
				System.out.print(root.str+" ");
				stack.push(root);
				root = root.left;
			}
			if(!stack.isEmpty()){	//如果栈不为空,则从栈中取出元素
				root = stack.pop();
				root = root.right;
			}
				
		}
	}

使用非递归方式

代码过程说明:

1)访问任意结点p,并将结点p压入栈;

2)判断结点p的左孩子是否为空,如果为空,就从栈中取出栈顶结点并进行出栈操作,并将出去的栈顶结点的右孩子置为当前的结点p,循环至1),如果不为空,则将结点p的左孩子置为当前结点p;

3)知道栈为空且p为NULL,则遍历结束;

使用栈的目的是为了以后能通过栈中的结点找到该结点的右孩子

前序非递归遍历参考资料

https://www.bilibili.com/video/av15550091?from=search&seid=4678713895339943928

http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html#!comments

2)中序遍历的两种方式:

中序遍历递归方式:

	public void inOrder(Node x){
		if(x==null)
			return;
		inOrder(x.left);
		System.out.print(x.str+" ");
		inOrder(x.right);
	}
中序遍历非递归方式:
	public void inOrder(Node root){
		Stack<Node> stack = new Stack<>();
		while(root!=null||!stack.isEmpty()){
			while(root!=null){
				stack.push(root);
				root = root.left;
			}
			if(!stack.isEmpty()){
				root = stack.pop();
				System.out.print(root.str+" ");  //这一点和前序不同,每次从栈中取出的时候打印
				root = root.right;
			}
		}
	}

对于任意结点P

1)若其左孩子不为空,则将其左孩子入栈并将p的左孩子设置为当前的p,然后对当前结点p再进行相同的处理

2)若其左孩子为空,则取出栈顶元素并进行出栈操作,打印出该栈顶结点,然后将栈顶结点的右孩子设置为p,重复1)

3)直到p为空且栈为空则遍历结束。

3)后序遍历的两种方式

	public void inOrder(Node x){
		if(x==null)
			return;
		inOrder(x.left);
		inOrder(x.right);
	        System.out.println(x.str+" ");
	}

递归方式:

3.二叉树的镜像按照前序遍历的过程来操作

代码示例:

	public void postOrder(Node x)
	{
		if(x==null)
		  return;
		postOrder(x.left);
		postOrder(x.right);
		System.out.print(x.str+" ");
	}
通过前序遍历的顺序逐个交换一个结点的左子树和右子树。

4.二叉树的深度按照后序遍历的过程来操作

代码实现:

	public int treeDepth(Node x){
		if(x==null){
			return 0;
		}
		int n1 = treeDepth(x.left);
		int n2 = treeDepth(x.right);
		if(n1>n2){
			n1++;
		}else{
			n2++;
		}
		return Math.max(n1, n2);
	}

说明:二叉树的最大深度可以看成是二叉树的后续遍历,后续遍历是自底向上,自左向右的移动,可以理解为动态规划问题。

5.二叉树的层序遍历

	public void levelOrder(Node x)
	{
		if(x==null)
			return;
		Queue<Node> q = new LinkedList<>();	 //链表也可以实现队列的功能
		q.add(x);
		while(!q.isEmpty())
		{
			Node n = q.poll();
			System.out.print(n.data+" ");
			if(n.left!=null)			//这边的判断要加入,因为队列中不能放入空
				q.add(n.left);
			if(n.right!=null)
				q.add(n.right);
		}
	}

1)将头结点入队列

2)将头结点出队列,获取头结点,并判断头结点的左子树和右子树是否为空,如果不为空,将它们压入队列

3)重复上面的操作,每次一个结点出队列,都会将它的左右结点压入队列(在左右结点不为空的情况下)

记住一点:每次从队列尾部取出一结点的同时,都要将给结点的左孩子(如果存在的情况下)和右孩子(如果存在的情况下)插入到队列中。

思想类同图中的广度搜索优先

6.二叉树的几个特征:

中序遍历:将二叉树的结点投影到平面,从左到右就是中序遍历的结果

前序遍历:二叉树的前序遍历得到的序列中,第一个结点是根节点的值

后序遍历:二叉树的后序遍历得到的序列中,最后一个结点是根结点的值

猜你喜欢

转载自blog.csdn.net/chenkaibsw/article/details/80067179