1、树结构的介绍
见视频1解析。
2、二分搜索树的基础
二叉树的介绍如下:
二分搜索树的介绍
注意,我们二分搜索树存储的元素必须具有可比较性,为了是存储的元素对象具有可比较性,元素类必须实现Comparable<E>
接口,并复写接口的 compareTo(Object obj)
方法以实现比较性。
关于前序、中序、后序遍历的总结如下,注意理解他们为什么是哪个样子的!
1、前序:先处理本结点(这里是打印本结点),然后处理以左孩子结点为根的左子树所有结点,处理以右孩子结点为根的右子树所有结点。 在左/右子树里面,同样先处理本子树的根结点,再处理下一级左子树所有结点,再处理下一级的右子树所有结点。
2、中序:先处理本结点的左子树所有结点,再处理本结点,再处理本结点右子树所有结点。对于左子树或者右子树,同样是先处理下一级左子树所有结点,再处理当前根结点,再处理下一级右子树所有结点.
中序遍历的结果就是当前二分搜索树所有元素排序后的结果!!!
3、总结:先处理本结点的左子树所有结点,再处理本结点右子树所有结点,最后处理本结点。 对于左子树或者右子树,同样是先处理下一级左子树所有结点,再处理下一级右子树所有结点,最后处理当前根结点。
想要快速找出二分搜索树前序、中序、后序排列的结果,不需要像视频8那样苦苦寻找,我们遵循以下规律即可:
前序:对于所有的结点,处理顺序是:当前结点——左孩子结点——右孩子结点,直到左右孩子结点为null,则直接结束递归,返回上一级的递归;
中序:对于所有的结点,处理顺序是:左孩子结点——当前结点——右孩子结点,直到左右孩子结点为null,则直接结束递归,返回上一级的递归;
后序:对于所有的结点,处理顺序是:左孩子结点——右孩子结点——当前结点,直到左右孩子结点为null,则直接结束递归,返回上一级的递归;
需要注意的是,这些是对于所有结点适用!!!必须一直寻找左右孩子结点处理,直到当前结点为叶子结点,就不需要再考虑其左右孩子结点(都为null),就可以直接返回叶子结点!
二分搜索树的递归实现代码如下:(注意对比递归方法的宏观语意以及微观上是如何实现的。)
package com.lkj;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
//注意!泛型参数必须继承Comparable接口来达到自己的泛型实例之间能相互比较的目的。
public class BinarySearchTree<E extends Comparable<E>> //泛型参数不是实现接口,而是继承接口extends,
{
//首先定义二分搜索树结点类
private class Node
{
//将内部类的属性定义为public,这样外部类可以很容易操作他们
public E e;
public Node left , right;//指向左孩子与右孩子的指针
public Node(E e)
{
this.e = e;
left = null;
right = null;
}
}
//下面定义二分搜索树的属性:根节点、二分搜索树元素个数:size (外部类的属性必须定义为private)
private Node root;
private int size;
//初始化二分搜索树,没有结点(根节点为null)
public BinarySearchTree()
{
root = null;
size = 0;
}
//树的元素个数
public int size()
{
return size;
}
//树是否为空
public boolean isEmpty()
{
return size==0;
}
//----------------------------------------------------------------添加
// 向二分搜索树中添加新的结点,结点的元素是e
public void add(E e)
{
//如果根结点是null,创建一个新的结点对象 new Node(e) 赋予根结点
if(root == null)
{
root = new Node(e);
size++;//注意将树元素个数+1
}
else
{
//如果根结点不为null,以根结点为基础,进行结点的添加(二叉树都是从根结点展开的)
//因为要进行递归添加,我们创建一个新的方法
add(root, e);
}
}
// 向以node为根的二分搜索树中插入结点(结点元素为e),递归算法。(这个方法不需要对用户暴露,因此设置为private)
private void add(Node node, E e)
{
//E 类已经实现Comparable接口,具有比较性,使用equals()方法可以比较对象是否相等,使用compareTo()方法可以比较对象大小。
/*
1、解决最基本的问题(递归终止条件):如果添加的元素与二叉树某个结点的元素相等,不添加;否则在左还在或者右孩子找到一个合适的位置添加
-------------------------------------------------
*/
//如果要插入的数据与根结点的数据相同,直接结束添加(二分搜索树的子树的元素必须与根结点的元素不同!)
if(e.equals(node.e))
return;
//如果新结点的元素e小于根结点元素,且左孩子为null,说明新的结点添加到左孩子的位置
else if(e.compareTo(node.e)<0 && node.left==null)
{
node.left = new Node(e);
size++;//注意将树元素个数+1
return;//我们只添加一个,添加完毕后记得结束整个函数
}
//如果新结点的元素e大于根结点元素,且右孩子为null,说明新的结点添加到右孩子的位置
else if(e.compareTo(node.e)>0 && node.right==null)
{
node.right = new Node(e);
size++;
return;