二叉树常见方法整理(1 遍历)

标签: 二叉树 遍历
10人阅读 评论(0) 收藏 举报
分类:

最近在看jdk的时候,发现一些底层还是使用了二叉树的相关知识,由此可以扩展开红黑树,或者MySQL的索引B+树。

补充一些知识点。

二叉树:

1、深度优先:递归,非递归实现方式
  1)先序遍历:先访问根节点,再依次访问左子树和右子树
  2)中序遍历:先访问左子树,再访问根节点吗,最后访问右子树
  3)后序遍历:先访问左子树,再访问右子树,最后访问根节点

        其中后序遍历是最复杂的。:举例两种不同的实现方式:

       a)   对于任意节点current,若该节点不为空则访问该节点后再将节点压栈,并将左子树节点置为current,重复此操作,直到current为空。 若左子树为空,取栈顶节点的右子树,如果右子树为空或右子树刚访问过,则访问该节点,并将preNode置为该节点 

      b)要保证根结点在左孩子和右孩子访问之后才干访问,因此对于任一结点P。先将其入栈。假设P不存在左孩子和右孩子。则能够直接访问它;或者P存在左孩子或者右孩子。可是其左孩子和右孩子都已被访问过了。

   对我来说,其中b更容易理解一些,还有双栈的实现方式更难理解就没贴。

2、广度优先

    按照树的深度,一层一层的访问树的节点。


节点类

package com.daojia.collect;
/**
 * 
 * @author daojia
 *
 */
public class Node {

	  int  value;  
	  Node leftChild;  
	  Node rightChild; 
	  
	  Node(int value) {  
	        this.value = value;  
	  }  
	      
	  public void display() {  
	     System.out.print(this.value + ",");  
	  }  
	  
	   @Override  
	 public String toString() {	        
	    return String.valueOf(value);  
	 }  
	
}
package com.daojia.collect;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

public class Btree {

	 private Node root = null;  
     
	 Btree(int value) {  
	        root = new Node(value);  
	        root.leftChild  = null;  
	        root.rightChild = null;  
	    }  
	//查找  
	    public Node findKey(int value) {
	    	Node current  = root ;
	    	while(true){
	    		if(current.value== value)
	    		{
	    			return current;
	    		}
	    		else if(current.value>value){
	    			
	    			 current = current.leftChild;
	    		}else if(current.value < value){
	    			current = current.rightChild;
	    		}
	    		if(current == null){
	    			return null;
	    		}
	    	}	    	
	
	    }   
	  //插入  
	        public Node insert(int value) {
	        	String error = null;  
	        	  
	        	Node node = new Node(value);  
	        	if (root == null) {  
	        	    root = node;  
	        	    root.leftChild  = null;  
	        	    root.rightChild = null;  
	        	} else {  
	        	    Node current = root;  
	        	    Node parent = null;  
	        	    while (true) {  
	        	        if (value < current.value) {  
	        	            parent = current;  
	        	            current = current.leftChild;  
	        	            if (current == null) {  
	        	                parent.leftChild = node;  
	        	                break;  
	        	            }  
	        	        } else if (value > current.value) {  
	        	            parent = current;  
	        	            current = current.rightChild;  
	        	            if (current == null) {  
	        	                parent.rightChild = node;  
	        	                break;  
	        	            }  
	        	        } else {  
	        	            System.out.println("exists");
	        	            break;
	        	        }     
	        	    } // end of while  
	        	}
	        	return node;
	        }  
	        //中序遍历递归操作  
	        public void inOrderTraverse() {
	            System.out.print("中序递归:");
	        	 inOrderTraverse(root);
	        	 System.out.println();
	        }
	        /**
	         * (递归)先遍历左子树,在跟节点,再遍历右子树
	         * @param node
	         */
	        private void inOrderTraverse(Node node) {  
	            if (node == null)   
	                return ;  
	        
	            inOrderTraverse(node.leftChild);  
	            node.display();  
	            inOrderTraverse(node.rightChild);  
	        }
	        /**
	         * 非递归遍历
	         * 1)对于任意节点current,若该节点不为空则将该节点压栈,并将左子树节点置为current,重复此操作,直到current为空。 
	         * 2)若左子树为空,栈顶节点出栈,访问节点后将该节点的右子树置为current 
	         * 3) 重复1、2步操作,直到current为空且栈内节点为空。 
	         */
	        public  ArrayList<Integer> inOrderByStack() {
	        	System.out.print("中序非递归:");
	        	ArrayList<Integer> list = new ArrayList<Integer>();
	        	Stack<Node> stack = new Stack<Node>();
	        	Node current = root;
	        	
	        	while(current != null ||!stack.isEmpty())
	        	{
	        		while(current != null){
	        		stack.push(current);
	        		current = current.leftChild;
	        		}
	        		
	        		if(!stack.isEmpty())
	        		{
	        			current =stack.pop();
	        			list.add(current.value);
	        			current = current.rightChild;
	        		}
	        	}
	        	return list;
	        }
	        //前序遍历  
	        public void preOrderTraverse() {
	        	System.out.print("前序遍历:");  
	            preOrderTraverse(root);
	            System.out.println("");    
	        }  
	        private void preOrderTraverse(Node node) {
	        	  if (node == null)   
		                return ;  
	        	  node.display();  
	        	  preOrderTraverse(node.leftChild);           
	        	  preOrderTraverse(node.rightChild);  
	        }
	        //前序遍历非递归操作  
	        public ArrayList<Integer> preOrderByStack() {
	        	System.out.print("前序遍历 非递归:");  
	        	ArrayList<Integer> list = new ArrayList<Integer>();
	        	Stack<Node> stack = new Stack<Node>();
	        	Node current = root;
	        	while(current != null || !stack.isEmpty())
	        	{
	        		while(current != null){
	        			stack.push(current);
	        			list.add(current.value);
	        			current = current.leftChild;
	        			
	        		}
	        		if( !stack.isEmpty()){
	        			current = stack.pop();
	        			current = current.rightChild;
	        		}
	        		
	        	}
	        	
	        	return list;
	        	
	        }  
	      //后序遍历  
	        public void postOrderTraverse() {
	        	System.out.print("后序遍历:");
	        	postOrderTraverse(root);
	        	System.out.println("");
	        }
	        private void postOrderTraverse(Node node){
	        	if(node == null){
	        		return;
	        	}
	        	postOrderTraverse(node.leftChild);
	        	postOrderTraverse(node.rightChild);
	        	node.display();
	        }
	        /**
	         * 1)对于任意节点current,若该节点不为空则访问该节点后再将节点压栈,并将左子树节点置为current,重复此操作,直到current为空。 
             * 2)若左子树为空,取栈顶节点的右子树,如果右子树为空或右子树刚访问过,则访问该节点,并将preNode置为该节点 
	         */
	        public ArrayList<Integer> postOrderByStack() {
	        	System.out.print("后序遍历 非递归:");  
	        	ArrayList<Integer> list = new ArrayList<Integer>();
	        	Stack<Node> stack = new Stack<Node>();
	        	Node current = root;
	        	Node preNode = null;  
	        	while(current != null || !stack.isEmpty())
	        	{
	        		while(current != null){
	        			stack.push(current);	        		
	        			current = current.leftChild;
	        			
	        		}
	        		if( !stack.isEmpty()){
	        			 current = stack.peek().rightChild;  
	                     if (current == null || current == preNode) {  
	                         current = stack.pop();  
	                         list.add(current.value);  
	                         preNode = current;  
	                         current = null;  
	                     }  	        				        			
	        		}	        		
	        	}
	        	
	        	return list;
	        } 
	        //后序遍历非递归操作 
	        public ArrayList<Integer> postOrderByStack2() {
	        	System.out.print("后序遍历 非递归:");  
	        	ArrayList<Integer> list = new ArrayList<Integer>();
	        	Stack<Node> stack = new Stack<Node>();
	        	Node current = null;
	        	Node preNode = null; 
	        	stack.push(root);
	        	while(!stack.isEmpty())
	        	{	        		
	        			 current = stack.peek();
	        			 //当前节点没有孩子节点或者左右孩子节点都被访问过
	                     if( (current.leftChild == null&¤t.rightChild== null) ||
	                    		 (current!= null&&(current.leftChild == preNode|| current.rightChild== preNode)) ) {  
	                         stack.pop();  
	                         list.add(current.value);  
	                         preNode = current;  
	                      
	                     }else{                    	 
	                  
	                    	 if(current.rightChild != null ){
	                    		 stack.push(current.rightChild);
	                    	 }
	                      	 if(current.leftChild != null ){
	                    		 stack.push(current.leftChild);
	                    	 }
	                     }
	        		       		
	        	}
	        	
	        	return list;
	        }
	        /**
	         * 广度优先遍历
	         * @return
	         */
	        public ArrayList<Integer> levelTraverse(){
	        	LinkedList<Node>  queue = new LinkedList<Node>();
	        	ArrayList<Integer> list = new ArrayList<Integer>();
	        	System.out.print("广度优先遍历 :");
	        	queue.add(root);
	        	while(!queue.isEmpty()){
	        		Node current = queue.poll();
	        		  list.add(current.value);
	        		  if(current.leftChild != null){
	        			  queue.add(current.leftChild);
	        		  }
	        		  if(current.rightChild != null){
	        			  queue.add(current.rightChild);
	        		  }
	        	}
				return list;
	        	
	        }
	        /**
	         * 得到最小值
	         * @return
	         */
	        public int getMinValue() {
	        	System.out.print("最小值:");
	        	Node current = root;
	        	while(true){
	        		
	        		if(current.leftChild == null)
	        		{
	        			return current.value;
	        		}
	        		current = current.leftChild;
	        	}
	        	
	        } 
	        //得到最大值
	        public int getMaxValue(){
	        	System.out.print("最大值:");
	        	Node current = root;
	        	while(true){
	        		
	        		if(current.rightChild == null)
	        		{
	        			return current.value;
	        		}
	        		current = current.rightChild;
	        	}
	        }
	    
	
	        public static void main(String[] args){
	        	
	        	Btree tree = new Btree(10);
	        	tree.insert(7);
	        	tree.insert(8);
	        	tree.insert(9);
	        	tree.insert(12);
	        	tree.insert(11);
	        	tree.insert(13);
	        	System.out.println(tree.insert(1));
	        	tree.inOrderTraverse();
	        	System.out.println(tree.inOrderByStack().toString());
	        	tree.preOrderTraverse();	        
	        	System.out.println(tree.preOrderByStack().toString());
	        	tree.postOrderTraverse();
	        	System.out.println(tree.postOrderByStack().toString());
	        	System.out.println(tree.postOrderByStack2().toString());
	        	System.out.println(tree.levelTraverse().toString());
	        	System.out.println(tree.getMinValue());
	        	System.out.println(tree.getMaxValue());
	        	
	        }
}

补充下栈的含义:pop 与peek,都返回栈顶的值。

不同点:peek 不改变栈的值(不删除栈顶的值),pop会把栈顶的值删除。

返回getMin栈的最小值。

运行结果:

1
中序递归:1,7,8,9,10,11,12,13,
中序非递归:[1, 7, 8, 9, 10, 11, 12, 13]
前序遍历:10,7,1,8,9,12,11,13,
前序遍历 非递归:[10, 7, 1, 8, 9, 12, 11, 13]
后序遍历:1,9,8,7,11,13,12,10,
后序遍历 非递归:[1, 9, 8, 7, 11, 13, 12, 10]
后序遍历 非递归:[1, 9, 8, 7, 11, 13, 12, 10]
广度优先遍历 :[10, 7, 12, 1, 8, 11, 13, 9]
最小值:1
最大值:13

待续:。。。 

参考:

https://blog.csdn.net/fengrunche/article/details/52305748

查看评论

Python算法实战视频课程--二叉树

二叉树是重要的抽象数据类型,解决很多问题时都需要它。通过本课我们学习这种重要的数据结构,本课注重实践,没有过多枯燥的理论,我们的重点放在编码实现各种算法,这对于熟练使用Python语言也是很有益处的。
  • 2016年05月11日 09:14

二叉树系列——二叉树的定义以及各种遍历方式

二叉树的三种遍历都是用递归实现,代码如下: //二叉树定义 struct BinaryTreeNode { int m_nValue; BinaryTreeNode* m_pLeft; Bina...
  • liuyi1207164339
  • liuyi1207164339
  • 2016-03-15 23:04:15
  • 428

二叉树的三种遍历方式总结

最近学了二叉树的三种遍历方式,即前序遍历,中序遍历,后序遍历三种,仔细思索后,在此简单总结一下。 一.二叉树示意图 假设有一颗二叉树如下: 二.遍历分析 每一颗二叉树由根节点,左子树,...
  • qq_35603331
  • qq_35603331
  • 2017-07-27 20:37:53
  • 486

关于二叉树的几种遍历方法

先说说二叉树的存储结构,跟很多其它模型一样,也有顺序和链式两种方式。前者虽然使用简单,但是存在浪费空间的问题,举个例子,下图的二叉树,用顺序的方式存储(0表示空,没有子树)是: 二叉树就是每个结点最...
  • pony_maggie
  • pony_maggie
  • 2014-08-05 20:57:46
  • 194534

数据结构——二叉树的递归与非递归遍历(先序,中序,后序)

实验项目五 二叉树基本操作的实现 课程名称:数据结构 实验项目名称:二叉树基本操作的实现 实验目的: 1.掌握树的基本操作—遍历。 实验要求: 1、 分别用递归和非递归的方法实现一棵...
  • l18339702017
  • l18339702017
  • 2017-12-18 20:32:09
  • 611

二叉树的四种遍历方式

1、前序遍历 前序遍历即先遍历完左子树,再访问父节点,最后遍历完右子树public class T1 { static class Node { int val; ...
  • gu_solo
  • gu_solo
  • 2016-09-14 12:32:51
  • 1284

创建二叉树的两种方法以及三种遍历方法

二叉树的两种创建方法和三种遍历方法 这里的两种创建方法,一种值得是 数据结构上面的创建方法: 方法一 代码如下: 二叉树的结构定义如下: typedef s...
  • yujin753
  • yujin753
  • 2015-01-26 11:32:43
  • 8918

二叉树三种遍历方法(根据两种排序求第三种的顺序)

1.已知先序和中序求后序      先序遍历的节点顺序是:ADCEFGHB,中序遍历是CDFEGHAB,则后序遍历的结果是  CFHGEDBA 解:1)根据先序遍历结果可知A是根节点,根据中序遍历...
  • jsjxy2009
  • jsjxy2009
  • 2014-09-28 09:15:49
  • 3099

二叉树 知道其他两种遍历方式求另一种

已知先序和中序 /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeN...
  • FengTwoYear
  • FengTwoYear
  • 2016-12-21 16:22:23
  • 751

利用两种遍历结果恢复二叉树并打印

  • 2013年12月04日 10:16
  • 634KB
  • 下载
    个人资料
    持之以恒
    等级:
    访问量: 20万+
    积分: 3519
    排名: 1万+
    最新评论