1. 对于大量数据输入时候,链表方式进行数据查找耗费时间太长,因此引入 简单的数据结构树,树的操作耗费的平均时间 log(N),
树定义:由一个或者多个结点组成集合,但是结点之间串联不形成环--叫做树,树根据 儿子的多小分为 二叉树和 B树,现在最重点研究的是二叉树(每一个树中结点最多有量个儿子结点)。
2. 二叉树:度不超过2的树---(对于树数据结构 最主要目标:利用这种特性数据结构如何快速定位所需要查找的数据)查找二叉树、平衡二叉树和红黑树
有如下特性:相比于度>2
1). 第 I 层最多 有2^(I-1)个结点
2). 深度K的二叉树 总结点数不超过 2^(K)-1
3). 叶子结点数 N0,度为2 的结点数N2,度为1 结点数N1: 根据总的 边数相同情况下 0*N0+2*N2+1*N1=总的结点数-1=N0+N1+N2-1
N0=N2+1;
3. 二叉树建立--树的定义 一种最自然方式采用递归方式建立二叉树,对树遍历 4中方式 前中后、层次遍历,对于数据输入 递归方式建立二叉树。 对于普通的二叉树,对于二叉搜索树等还有更加简便方式; 接下来 采用层次遍历和先序遍历方式 递归建立二叉树:
普通类型的二叉树 建立 使用递归的方式建立二叉树:
package com.offerr;
/**
* 利用层次遍历二叉树 */
public class CreatBinaryTree {
public static BinaryTree root;
public CreatBinaryTree(int array[],int Key)
{
if(Key>=1)
{ // 采用层次遍历 递归建立二叉树
root=Tree(array,0);
}
else
{
root=PreOrderTree(array);
System.out.println(Kindex);
}
}
/**
* 先序遍历的特性,必须 需要 成员变量 控制索引
* */
private int Kindex=0;
private BinaryTree PreOrderTree(int[] array) {
int val=array[Kindex++];// Kindex 代表数组索引,不管是否-1 ,不得不向前加1
if( val==-1)
return null;
BinaryTree Node=new BinaryTree(val);
Node.Left=PreOrderTree(array);
Node.Right=PreOrderTree(array);
return Node;
}
/**
* 层次遍历方式建立二叉树*/
public BinaryTree Tree(int[] array,int index) {
if(index>=array.length || array[index]<0)
return null;
BinaryTree Node=new BinaryTree(array[index]);
Node.Left=Tree(array, 2*index+1);
Node.Right=Tree(array, 2*index+2);
return Node;
}
public void preShow(BinaryTree node) { // 先序遍历
if (node != null) {
System.out.print(node.val + " ");
preShow(node.Left);
preShow(node.Right);
}
}
public static void main(String[] args) {
int array[]={1,2,-1,5,-1,-1,3,-1,4,-1,-1};
CreatBinaryTree Tree=new CreatBinaryTree(array,0);
Tree.preShow(root);
}
}
class BinaryTree
{
public BinaryTree Left;
public BinaryTree Right;
public int val=0;
public BinaryTree()
{
this(0);
}
public BinaryTree(int val) {
this.Left=null;
this.Right=null;
this.val=val;
}
}
4. BST 二叉查找树:
1.树一个最重要的应用在于 树的查找时间复杂度o(logN),
二叉查找树相比于普通二叉树 树的结点有一定的规律:任何结点X,它的左子树中所有项比X小,右子树中所有的值比X大,因此 在二叉树Insert 方法建立二叉树,不能够简单的递归的方式建立BST树 ,建立BST 主要 Insert,Remove,findMin,findMax等几个常用方法,
对于insert ,findMin,findMax等方法 确实没有多大的疑问,
但是 对于树这种逻辑结构,删除操作 有点困难,删除必须虑三种情况
1.叶子节点
2. 只有一个儿子节点
3.有俩个儿子 这里有两种策越:① 删除点的右子树的最小数据,因为此结点没有孩子结点,代替此结点
②寻找删除结点的左子树的最大数据代替此结点。
注意如果要删除结点是根结点 ,代替根结点值 只能是右子树的最小值代替,删除右子树。
由于在remove操作时候 特别某一个结点有 两个孩子,采取寻找删除结点的右子树的最小值点,同时删除此最小值结点在树中原先的位置
/* 找到最小值点,同时在树中删除此最小值结点*/
private BinaryNode<AnyType> findMinR(BinaryNode<AnyType> t) {
BinaryNode<AnyType> min=t.right;
BinaryNode<AnyType> parent=null;// 两种情况 直线斜树 和 不是斜树
while(min.left!=null)
{
parent=min;// 记录 min 父结点
min=min.left;
}
if(parent==null)
{// 表示 直线斜树
t.right=min.right;//直接删除min结点
}
else
{
parent.left=min.right;
}
return min;
}
BST 树整体代码:
package com.offerr;
public class BinarySearchTree<AnyType extends Comparable<? super AnyType>> {
private BinaryNode<AnyType> root;
public BinarySearchTree()
{
root=null;
}
private static class BinaryNode<AnyType>{
AnyType Element;
BinaryNode<AnyType> left;
BinaryNode<AnyType> right;
public BinaryNode(AnyType Element) {
this(Element,null,null);
}
public BinaryNode(AnyType element, BinaryNode<AnyType> object, BinaryNode<AnyType> object2) {
this.Element=element;
this.left=object;
this.right=object2;
}
}
public void insert(AnyType x)
{
root=insert(x,root);
}
public boolean contains(AnyType x)
{
return conatins(root,x);
}
public void remove(AnyType x)
{
remove(root,x);
}
public AnyType findMin() throws Exception
{
if (isEmpty())
throw new Exception("树是空树");
return findMin(root).Element;
}
public void makeEmpty()
{
root=null;
}
public boolean isEmpty()
{
return root==null;
}
/**
* Insert
* */
private BinaryNode<AnyType>insert(AnyType x, BinaryNode<AnyType> t) {
if(t==null)
return new BinaryNode<AnyType>(x);
int ComparableResult=x.compareTo(t.Element);
if(ComparableResult<0)
{
t.left=insert(x, t.left);
}else if(ComparableResult>0)
{
t.right=insert(x, t.right);
}
else {
;// 插入点 与树中某个结点值相同,不进行任何操作
}
return t;
}
/**
* BST 的 最小值 最小值 一定最左边的叶子结点
* @throws Exception
* */
private BinaryNode<AnyType> findMin(BinaryNode<AnyType> t) {
while(t.left!=null)
t=t.left;
return t;
}
private BinaryNode<AnyType> findMax(BinaryNode<AnyType> t) {
while(t.right!=null)
t=t.right;
return t;
}
/**
* BST 包含 某一个结点 ,循环
* */
private boolean conatins(BinaryNode<AnyType> t, AnyType x) {
if(t==null)
return false;
// 使用循环
while(t!=null)
{
int CompareResult=x.compareTo(t.Element);
if(CompareResult==0)// match
return true;
else if(CompareResult<0)
t=t.left;
else {
t=t.right;
}
}
return false;
}
/**
* 提供效率 不使用递归
* 判定被删除点是不是 根结点*/
private void remove(BinaryNode<AnyType> t, AnyType x) {
if(t==null)
return ;
// 定位到被删除的结点
BinaryNode<AnyType> p=null;
while(t!=null)
{
if(x.compareTo(t.Element)<0)
{
p=t;
t=t.left;
}
else if(x.compareTo(t.Element)>0)
{
p=t;
t=t.right;
}
else // 定位到被删除的结点
{
// 判断 被删除结点 是否是根结点 如果是根结点话,两个孩子
if(t.left==null && t.right==null)
{
if(p==null)
{
// 被删除结点 是根结点 并且 无孩子,说明此树只有一个结点
t=null;
}
else
{
if(p.left==t) // 待删除结点是父结点的 左孩子
p.left=t.left;
else
p.right=t.right;
}
}
else if(t.left==null || t.right==null )//有一个孩子
{
if(p==null) //判断删除结点 是否根结点
{
if(t.left!=null)
t=t.left;
if(t.right!=null)
t=t.right;
}
else // 被删除的点 不是 其根结点
{
if(t.left!=null) // 有左孩子
{
if(p.left==t)
p.left=t.left;
else
p.right=t.left;
}
if(t.right!=null)
{
if(p.left==t)
p.left=t.right;
else
p.right=t.right;
}
}
}
else // 有两个孩子
{
// 找到最小值点,同时删除最小值点在树中位置
BinaryNode<AnyType> min=findMinR(t); //
t.Element=min.Element;
}
}
}
}
/**
* 找到最小值点,同时在树中删除此最小值结点*/
private BinaryNode<AnyType> findMinR(BinaryNode<AnyType> t) {
BinaryNode<AnyType> min=t.right;
BinaryNode<AnyType> parent=null;// 两种情况 直线斜树 和 不是斜树
while(min.left!=null)
{
parent=min;// 记录 min 父结点
min=min.left;
}
if(parent==null)
{// 表示 直线斜树
t.right=min.right;//直接删除min结点
}
else
{
parent.left=min.right;
}
return min;
}
public void preShow(BinaryNode<Integer> node) { // 先序遍历
if (node != null) {
System.out.print(node.Element + " ");
preShow(node.left);
preShow(node.right);
}
}
public static void main(String [] args)
{
int array[]={6,5,9,4,7,10};
BinarySearchTree<Integer> bst=new BinarySearchTree<>();
for(int i=0;i<array.length;i++)
bst.insert(array[i]);
bst.preShow(bst.root);
BinaryNode<Integer> re=bst.root;
bst.remove(6);
System.out.println();
bst.preShow(bst.root);
}
}