一篇文章搞定二叉树的秘密(一篇文章搞定二叉树的秘密怎么写)

【知识点】

  • 为什么要学习二叉树
  • 二叉树的概念和特点
  • 二叉树的定义和创建
  • 二叉树的基本操作
  • 二叉树的遍历方式

1、为什么要学习二叉树

二叉树的知识更倾向于理论,我们在实际应用开发过程中直接使用得并不多,但是二叉树作为数据结构的一个重要的组成部分,在我们的面试过程中,会经常遇到二叉树知识相关问题,而且底层很多东西都是基于二叉树实现的,比如TreeMap、TreeSet、Linux的虚拟内存管理、数据库系统等,所以掌握二叉树的基本操作是相当有必要的。

2、树的概念和特点

我们这里来学习我们数据结构中的树,而不是现实生活中的树。但是它和现实生活中的树有着很多的相似之处,或者可以说数据结构的树是对现实生活中树的抽象。那么我们先来看看现实生活中树的样子,如下图:




看完了现实生活中树的样子后,就来看看数据结构中树的样子了,如下图:

树的定义

树是由n(n>=1)个有限节点组成的一个具有层次关系的集合。

树的特点:

  1. 每个节点有零个或多个子节点;
  2. 没有父节点的节点称为根节点;
  3. 每一个非根节点有且只有一个父节点;
  4. 除了根节点外,每个子节点可以分为多个不相交的子树。

3、二叉树的概念和特点

二叉树是一种特殊的树,在树的基础上添加约束条件:每个节点下最多只有两棵子树。它具有特点:

  1. 每个节点最多有两颗子树。
  2. 左子树和右子树是有顺序的,次序不能颠倒。
  3. 即使某节点只有一个子树,也要区分左右子树。



二叉树图

4、二叉树实现分析

1、一个二叉树节点有三个部分,一个是指向左子树的部分,一个是指向右子树的部分,另外一个是数据部分。可以把这个节点抽象成一个节点对象,节点对象有两个节点对象属性和一个数据属性。如下图:



2、一个二叉树有且只有一个根节点,其余的都是根节点的直接或间接子节点。所以可以把二叉树抽象成一个对象,该对象有一个节点类型的数据,用来保存根节点。如下图:



5、节点类和二叉树类的定义

1、通过刚刚的分析,首先要定义一个类:节点类,代码实现如下

/**
 * 节点类
 * @author pkxing
 *
 */
public class Node {
	// 节点内容
	int  value;
	// 左节点
    Node leftChild;  
    // 右节点
    Node rightChild;  
    
    public Node(int value) {  
        this.value = value;  
    }  
    @Override  
    public String toString() {  
        return String.valueOf(value);  
    }    
}


2、然后定义二叉树类,代码实现如下

/**
 * 二叉树类
 * @author pkxing
 *
 */
public class BinaryTree {
	// 根节点
	private Node root = null;
	// 构造方法
	// 有参数
	public BinaryTree(int value) {  
        root = new Node(value);  
        root.leftChild  = null;  
        root.rightChild = null;  
    }  
	// 无参数
	public BinaryTree(){}
}


6、二叉树的基本操作

需求:现有数组int a [ ] = {3,1,0,2,7,5,8,9},要求如下:

1.将数组中元素存储到二叉树中。

2.效果图如下:



二叉排序树的本质就是一颗二叉树,它具有如下特点:

  • 所有左节点的元素值小于其父节点的元素值.
  • 所有右节点的元素值大于其父节点的元素值.

添加节点

  • 添加元素流程图
  • 在二叉树类BinaryTree中定义成员方法,方法声明如下:

public boolean add(int value)

参数解析

value:节点的内容

返回值解析

true:表示添加成功

false:表示添加失败

  • 代码实现
/**
	* 插入节点
	* @param value  节点的值
	* @return 插入成功返回true,否则返回false
	*/
	public boolean add(int value) {
		// 定义变量用来标识是否插入成功,默认值表示插入成功
		boolean success = true;
		// 根据内容创建节点对象
		Node node = new Node(value);
		// 判断根节点是否为null,如果为null,则将node对象作为根节点对象
		if (root == null) { // 没有根节点
			// 将node对象作为根节点对象
			root = node;
			// 设置左右节点为null
			root.leftChild = null;
			root.rightChild = null;
		} else { // 有根据节点
			// 定义变量记录当前遍历的节点对象:默认从根节点对象开始遍历
			Node current = root;
			// 遍历树上的所有节点对象
			while (true) {
				if (value < current.value) {
					// 来到这里说明node对象应该添加到current节点对象的左边
					if (current.leftChild == null) {
						current.leftChild = node;
						break;
					}
					// 获得current节点的左子节点对象,并赋值给current变量
					current = current.leftChild;
				} else if (value > current.value) {
					// 来到这里说明node对象应该添加到current节点对象的右边
					if (current.rightChild == null) {
						current.rightChild = node;
						break;
					}
					// 获得current节点的右子节点对象,并赋值给current变量
					current = current.rightChild;
				} else { // value值已经存在了,则直接返回false
					success = false;
					break;
				}
			} 
		}
		// 插入成功
		return success;
}

查询节点

  • 查询思路

先查找其根节点,如果根节点的元素值和要查找的元素值相等,则返回该根节点对象。否则,比较根节点的元素和要查找的元素,

如果元素值大于根节点元素值,则查询其右子树。

如果元素值小于根节点元素值,则查询其左子树。


  • 在二叉树类BinaryTree中定义一个查询的成员方法,方法声明如下:

public Node get(int value)

参数解析:value:要查找节点内容。

返回值解析:查询到的节点对象

  • 代码实现
/**
	* 根据节点内容查找节点对象
	* @param value 内容
	* @return 查找到的节点对象,如果没有则返回null
	*/
	public Node get(int value) {  
		// 定义变量记录当前遍历的节点对象,默认从根节点开始遍历
	    Node current = root;  
	    while (true) {  
	    	// 判断value和current节点对象的value是否相同
	        if (value == current.value) {  
	        	// 来到这里则说明current节点对象就是要查找的对象,直接返回即可
	            return current;  
	        } else if (value < current.value) {  
	        	// 来到这里说明要查找的节点对象是在current节点的左子树上
	            current = current.leftChild;  
	        } else if (value > current.value) {  
	        	// 来到这里说明要查找的节点对象是在current节点的右子树上
	            current = current.rightChild;  
	        } 
	        // 如果current节点对象为null,则说明没有找到对应的节点对象
	        if (current == null) {  
	            return null;  
	        }  
	    }  
	}  

二叉树的遍历方式

遍历流程:先遍历左子树,再访问根节点,最后遍历右子树.

代码实现如下

/**
	* 先遍历左子树,再访问根节点,最后遍历右子树;
	* 
	* @param node
	*/
	public void inOrder(Node node) { 
		if (node != null) {
			inOrder(node.getLeftChild());
			System.out.println(node);
			inOrder(node.getRightChild());
		}
	}

重写toString方法

/**
	 * 将指定节点下的所有子节点的内容按顺序输出
	 * @param node
	 */
	public void order2(Node node,List<Integer> list){
		if(node == null) return;
		// 先遍历node的左节点
		order2(node.getLeftChild(),list);
		// 将节点内容添加集合中
		list.add(node.getValue());
		// 遍历node的右节点
		order2(node.getRightChild(),list);
	}
	
	@Override
	public String toString() {
		// 创建集合对象
		List<Integer> list = new ArrayList<>();
		order2(root,list);
		return list.toString();
	}


学废了吗?

原文链接:,转发请注明来源!