package com.AdvancedDataStructure.BSTTree;
import java.util.LinkedList;
import java.util.Stack;
/**
* @Created with IntelliJ IDEA
* @Description: BST树代码演示
* @Package: com.AdvancedDataStructure.BSTTree
* @author: FLy-Fly-Zhang
* @Date: 2019/6/26
* @Time: 19:09
*/
class BSTNode <T extends Comparable<T>>{
private T data;
private BSTNode<T> left;
private BSTNode<T> right;
public BSTNode(T data,BSTNode<T> left,BSTNode<T> right){
this.data=data;
this.left=left;
this.right=right;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public BSTNode<T> getLeft() {
return left;
}
public void setLeft(BSTNode left) {
this.left = left;
}
public BSTNode<T> getRight() {
return right;
}
public void setRight(BSTNode right) {
this.right = right;
}
}
class BST <T extends Comparable<T>>{
private BSTNode<T> root; //根节点
/*
* @Description : BST
* @param null
* @return :
* @exception :
* @date : 2019/6/26 19:12
*/
public BST(){
this.root=null;
}
/*
* @Description : 添加节点,前驱实现
* @param null
* @return :
* @exception :
* @date : 2019/6/26 20:20
*/
public void non_insert(T data){
//判断如果root是否null,如果为null,直接生成根节点
if(this.root==null){
this.root=new BSTNode<T>(data,null,null);
return;
}
//
BSTNode tmp=root;
//如果root不为空,从根节点进行搜索。
while(true){
if(tmp.getData().compareTo(data)>0){
if(tmp.getLeft()==null){
//生成新结点,把节点的地址,写入父节点相应的地址域
tmp.setLeft(new BSTNode<T>(data,null,null));
return;
}
tmp=tmp.getLeft();
}else if(tmp.getData().compareTo(data)<0){
if(tmp.getRight()==null){
tmp.setRight(new BSTNode<T>(data,null,null));
return;
}
tmp=tmp.getRight();
}else{
return;
}
}
}
public void insert(T data){
if(this.root==null){
this.root=new BSTNode<>(data,null,null);
return;
}
insert(this.root,data);
}
/*
* @Description : 结点插入,递归实现
* @param null
* @return :
* @exception :
* @date : 2019/6/29 16:10
*/
private BSTNode<T> insert(BSTNode<T> root, T data) {
if(root==null)
return new BSTNode<T>(data,null,null);
//左子树递归
if(root.getData().compareTo(data)>0){
//在非插入的父节点,没有必要在进行结点赋值
//但是这样的写,又多了一次判断,指令也更多,
//没有必要这样写。
if(root.getLeft()!=null){
insert(root.getLeft(),data);
}else{
root.setLeft(insert(root.getLeft(),data));
}
//右子树递归
}else if(root.getData().compareTo(data)<0){
root.setRight(insert(root.getRight(),data));
}
return root;
}
//删除有两个孩子的节点:应该找删除节点的前驱结点或者后继结点,
// 用前驱或者后继把当前删除结点的值覆盖点,然后直接删除前驱或者后继结点
//前驱结点:待删除结点左子树中,值最大的结点
//后继结点:待删除结点右子树中,值最小的结点
//删除有一个孩子的节点
//删除没有孩子的节点
/*
* @Description : 删除结点,前驱实现
* @param data
* @return : void
* @exception :
* @date : 2019/6/29 14:49
*/
public void non_remove(T data){
//先搜索BST树,找到待删除结点
BSTNode<T> cur=this.root;
BSTNode<T> pre=null;
while(cur!=null){
if(cur.getData().compareTo(data)>0){
pre=cur;
cur=cur.getLeft();
}else if(cur.getData().compareTo(data)<0){
pre=cur;
cur=cur.getRight();
}else{
break;
}
}
if(cur==null)
return;
//判断删除结点是否有两个结点,如果有则用前驱的值代替,没有直接删除前驱
//注意,在用前驱结点替换掉要删除结点后,前驱前驱结点是需要被删除的,
//此时删除前驱结点就变成了有一个孩子的结点或者没有孩子的结点
if(cur.getLeft()!=null&&cur.getRight()!=null){
BSTNode<T> old=cur;
pre=cur;
//左子树的最大结点
cur=cur.getLeft();
while(cur.getRight()!=null){
pre=cur;
cur=cur.getLeft();
}
//前驱结点的值替代待删结点的值。
old.setData(cur.getData());
}
//删除有一个孩子的结点,或者没有孩子的结点
BSTNode child=cur.getLeft();
if(child==null)
child=cur.getRight();
//恰好删除的可能是根结点,那么直接进行else里面的操作会报空指针异常。
if(pre==null){
this.root=child;
}else{
if(pre.getLeft()==cur){
pre.setLeft(child);
}else{
pre.setRight(child);
}
}
}
/*
* @Description : 删除结点,后继结点实现
* @param data
* @return : void
* @exception :
* @date : 2019/6/29 14:50
*/
public void non_remove1(T data){
BSTNode<T> pre=null;
BSTNode<T> cur=this.root;
while(cur!=null){
if(cur.getData().compareTo(data)<0){
pre=cur;
cur=cur.getRight();
}else if(cur.getData().compareTo(data)>0){
pre=cur;
cur=cur.getLeft();
}else{
break;
}
}
//未找到结点
if(cur==null)
return;
if(cur.getLeft()!=null&&cur.getRight()!=null){
BSTNode<T> old=cur;
pre=cur;
//右子树的最小结点
cur=cur.getRight();
while(cur.getLeft()!=null){
pre=cur;
cur=cur.getLeft();
}
old.setData(cur.getData());
}
BSTNode<T> child=cur.getLeft();
if(child==null)
child=cur.getRight();
//要删除结点为根结点,
if(pre==null){
this.root=child;
}else{
if(pre.getLeft()==cur){
pre.setLeft(child);
}else{
pre.setRight(child);
}
}
}
public void remove(T val){
//防止删除的是头结点
this.root=remove(this.root,val);
}
/*
* @Description :
* 递归删除BST的结点和循环删除的最大区别是,
* 循环我们需要始终保证前驱结点的链接,目的在于
* 删除一个孩子或者没有孩子的结点时,可以让父结点和孩子连接起来
* 递归的话,我们并没有保存其前驱结点,但是我们在递归的时候,
* 实际上每一次递归都是重新连接当前的左右结点
* root.setLeft(remove(root.getLeft(),pre.getData()));
* 这一步以及下面的两步实际上就是将左右孩子和父结点连接起来。
* @param null
* @return :
* @exception :
* @date : 2019/7/3 15:36
*/
private BSTNode<T> remove(BSTNode<T> root, T val) {
if(root==null)
return null;
//每一步只关注自己应该连接哪些连接
//要删除的结点在左边
if(root.getData().compareTo(val)>0){
root.setLeft(remove(root.getLeft(),val));
//要删除的结点在右边
}else if(root.getData().compareTo(val)<0){
root.setRight(remove(root.getRight(),val));
//找到要删除的结点
}else{
//两个结点的情况的删除
if(root.getLeft()!=null&&root.getRight()!=null){
BSTNode<T> pre=root.getLeft();
//找前驱
while(pre.getRight()!=null){
pre=pre.getRight();
}
//将前驱结点赋值给要删除结点
root.setData(pre.getData());
//删除前驱结点==》等效于只有一个孩子的删除或者没有孩子的删除
root.setLeft(remove(root.getLeft(),pre.getData()));
//只有一个孩子或者没有孩子的删除
}else if(root.getLeft()!=null){
return root.getLeft();
}else if(root.getRight()!=null){
return root.getRight();
}else{
return null;
}
}
return root;
}
private BSTNode<T> remove1(BSTNode<T> root,T data){
if(root==null)
return null;
if(root.getData().compareTo(data)>0){
root.setLeft(remove1(root.getLeft(),data));
}else if(root.getData().compareTo(data)<0){
root.setRight(remove1(root.getRight(),data));
}else{
if(root.getLeft()!=null&&root.getRight()!=null){
BSTNode<T> cur=root.getRight();
while(cur.getLeft()!=null){
cur=cur.getLeft();
}
root.setData(cur.getData());
root.setRight(remove1(root.getRight(),cur.getData()));
}else if(root.getLeft()!=null){
return root.getLeft();
}else if(root.getRight()!=null){
return root.getRight();
}else{
return null;
}
}
return null;
}
/*
* @Description : 查询二叉树中是否存在某个元素
* @param data
* @return : boolean
* @exception :
* @date : 2019/6/29 14:52
*/
public BSTNode<T> non_query(T data){
BSTNode cur=this.root;
while(cur!=null){
if(cur.getData().compareTo(data)>0){
cur=cur.getLeft();
}else if(cur.getData().compareTo(data)<0){
cur=cur.getRight();
}else{
return cur;
}
}
return null;
}
/*
* @Description : 递归实现查找元素
* @param null
* @return :
* @exception :
* @date : 2019/6/29 16:19
*/
public boolean query(T data){
return query(this.root,data);
}
private boolean query(BSTNode<T> root, T data) {
if(root==null)
return false;
if(root.getData().compareTo(data)>0){
return query(root.getLeft(),data);
}else if(root.getData().compareTo(data)<0){
return query(root.getRight(),data);
}else{
return true;
}
}
/*
* @Description : 前序遍历BST树API接口
* VLR:
* @param null
* @return :
* @exception :
* @date : 2019/6/29 9:55
*/
public void preOrder(){
System.out.print("前序遍历: ");
preOrder(this.root);
}
/*
* @Description : 前序遍历递归调用
* @param null
* @return :
* @exception :
* @date : 2019/6/29 9:57
*/
private void preOrder(BSTNode<T> root){
if(root!=null){
System.out.print(root.getData()+" ");
preOrder(root.getLeft());
preOrder(root.getRight());
}
}
/*
* @Description :前序遍历,非递归实现
* 使用栈作为存储结构
* @param null
* @return :
* @exception :
* @date : 2019/7/1 13:29
*/
public void non_preOrder(){
if(this.root==null)
return;
BSTNode<T> tmp=this.root;
Stack<BSTNode<T>> stack=new Stack();
stack.push(tmp);
while(!stack.empty()){
//VLR因为是先取出L在取出,R
//根据stack的数据结构需要先存R在取L才能保证先遍历L
tmp=stack.pop();//V
System.out.print(tmp.getData());
if(tmp.getRight()!=null)
stack.push(tmp.getRight());
if(tmp.getLeft()!=null)
stack.push(tmp.getLeft());
}
System.out.println();
}
/*
* @Description : 中序
* @param null
* @return :
* @exception :
* @date : 2019/6/29 10:04
*/
public void inOder(){
System.out.print("中序遍历:");
inOder(this.root);
}
private void inOder(BSTNode<T> root){
if(root!=null){
inOder(root.getLeft()); //L
System.out.print(root.getData()+" "); //V
inOder(root.getRight()); //R
}
}
public void non_inOrder(){
if(this.root==null)
return;
BSTNode<T> tmp=this.root;
//linkedlist的pop和push操作都是采用头插头删除
//这样其实也是一个类似与栈的数据结构
LinkedList<BSTNode<T>> stack=new LinkedList<>();
//LVR
while(!stack.isEmpty()|| tmp!=null){
//当前结点不为空,一直寻找左孩子
if(tmp!=null){
stack.push(tmp);
tmp=tmp.getLeft();
}else{
//为空时,找到V,然后在将R压入栈里面
tmp=stack.pop();
System.out.print(tmp.getData());
tmp=tmp.getRight(); //R可能也有自己的左孩子
}
}
System.out.println();
}
/*
* @Description : 后序遍历
* @param null
* @return :
* @exception :
* @date : 2019/6/29 10:20
*/
public void postOrder(){
System.out.print("后序遍历: ");
postOrder(this.root);
}
private void postOrder(BSTNode<T> root){
if(root!=null){
postOrder(root.getLeft());//L
postOrder(root.getRight());//R
System.out.print(root.getData()+" "); //V
}
}
public void non_postOrder(){
if(this.root==null)
return;
Stack<BSTNode<T>> stack=new Stack();
Stack<BSTNode<T>> stack1=new Stack();
BSTNode<T> tmp=this.root;
stack.push(tmp);
//对于后序遍历LRV,采用的两个栈的模式,将V
//先压入stack1栈中,然后再将左右孩子压入一个stack中,
//在下一次循环的时候,右孩子先出栈,然后再将其压入
//stack1。
//这样相当于实现了VRL的入栈顺序,根据栈的数据结构,
//那么出栈的顺序为LRV。
while(!stack.empty()){
tmp=stack.pop();
stack1.push(tmp);
if(tmp.getLeft()!=null){
stack.push(tmp.getLeft());
}
if(tmp.getRight()!=null){
stack.push(tmp.getRight());
}
}
while(!stack1.empty()){
System.out.print(stack1.pop().getData());
}
System.out.println();
}
/*
* @Description : 返回BST树中所有节点个数的API
* @param null
* @return :
* @exception :
* @date : 2019/6/29 10:08
*/
public int number(){
return number(this.root);
}
private int number(BSTNode<T> root){
if(root!=null){
return number(root.getLeft())+number(root.getRight())+1;
}
return 0;
}
/*
* @Description : 树的高度
* @param null
* @return :
* @exception :
* @date : 2019/6/29 10:19
*/
public int level(){
return level(this.root);
}
private int level(BSTNode<T> root){
int l=0;
int r=0;
if(root!=null){
l=level(root.getLeft())+1;
r=level(root.getRight())+1;
}
return l>r? l:r;
}
/*
* @Description : 层序遍历BST
* @param null
* @return :
* @exception :
* @date : 2019/6/29 10:24
*/
public void levelOrder(){
int level=level();
//有多少层遍历多少次
for (int i = 0; i <level ; i++) {
levelOrder(this.root,i);
}
}
/*
* @Description : 层序遍历递归实现
* @param null
* @return :
* @exception :
* @date : 2019/6/29 10:33
*/
private void levelOrder(BSTNode<T> root,int i){
if(root!=null){
//到达要遍历的层。
if(i==0){
System.out.print(root.getData()+" ");
return; //这里return需要+,要不然会继续深度遍历。
}
//当前层数不是需要遍历的层数,继续进行深入
levelOrder(root.getLeft(),i-1);
levelOrder(root.getRight(),i-1);
}
}
/*
* @Description : BST镜像的递归实现
* 总结下来就是左右子树互换
* @param root
* @return : void
* @exception :
* @date : 2019/6/29 14:58
*/
public void mirror(BSTNode<T> root){
if(root==null){
return ;
}
//左右子树互换
BSTNode<T> tmp=root.getLeft();
root.setLeft(root.getRight());
root.setRight(tmp);
//继续将子树的左右子树进行互换
mirror(root.getLeft());
mirror(root.getRight());
}
/*
* @Description : 区间元素的查找
* 使用的是中序遍历的方式因为中序遍历是有序的
* @param null
* @return :
* @exception :
* @date : 2019/6/29 11:28
*/
public void printAreaDatas(T begin,T end){
printAreaDatas(begin,end,this.root);
}
private void printAreaDatas(T begin,T end,BSTNode<T> root){
if(root==null){
return;
}
//当前节点的值小于begin,不用再递归左子树
if(root.getData().compareTo(begin)>0){
printAreaDatas(begin,end,root.getLeft()); //L
}
if(root.getData().compareTo(begin)>=0&& root.getData().compareTo(end)<=0){
System.out.print(root.getData()); //V
}
//当前节点的值小于end,才有必须要进行右子树递归
if(root.getData().compareTo(end)<0){
printAreaDatas(begin,end,root.getRight()); //R
}
}
/*
* @Description : 判断二叉树是不是BST树
* @param null
* @return :
* @exception :
* @date : 2019/6/29 11:34
*/
public boolean isBSTree(){
T value=null;
return isBSTree(this.root,value);
}
/*
* @Description :
* 判断一个数是不是BST树,我们采用中序遍历的方式
* 每次保留前一个V,当其满足前面小于后面的要求时,
* 那么其就是BST树
* @param root
* @param value
* @return : boolean
* @exception :
* @date : 2019/6/29 12:03
*/
private boolean isBSTree(BSTNode<T> root,T value){
if(root==null){
return true;
}
T val=root.getData();
//左子树不满足BST树性质,直接返回,不用递归
//这里的value不用更新,因为此value只是传进来上一个value
//当在下面和val比较后再将val进行更新
//在最深度的左边遍历中,root==null,直接返回true。
if(!isBSTree(root.getLeft(),value))
return false;
//当前节点与中序遍历的前一个节点进行比较
//value!=null,主要是为了过滤root==null是返回的value==null的值
if(value!=null&&value.compareTo(val)>0)
return false;
//当前结点满足中序,将当前结点值传入与下一个V进行比较。
return isBSTree(root.getRight(),val);
}
/*
* @Description : 返回两个节点的最近祖先节点。
* @param null
* @return :
* @exception :
* @date : 2019/6/29 12:10
*/
public T getLCA(T data1,T data2){
return getLCA(this.root,data1,data2);
}
private T getLCA(BSTNode<T> root,T data1,T data2){
if(root==null){
return null;
}
//两个节点均在当前节点的左子树
if(root.getData().compareTo(data1)> 0&& root.getData().compareTo(data2)>0){
return getLCA(root.getLeft(),data1,data2);
//两个节点均在当前节点的右子树
}else if(root.getData().compareTo(data1)<0&&root.getData().compareTo(data2)<0){
return getLCA(root.getRight(),data1,data2);
//一个在左子树一个在右子树,那么当前节点恰好是其最近的公共祖先节点
}else{
return root.getData();
}
}
/*
* @Description : 返回中序遍历的倒数第k个节点。
* 中序遍历是LVR,其结果为升序
* 那么我们采用RVL.那么其结果为降序。
* 那么第k个元素,就是其倒数第k个结点。
* @param null
* @return :
* @exception :
* @date : 2019/6/29 12:30
*/
private int k;
public T getOrderValue(int k){
this.k=k;
// return getOrderValue(this.root);
return getOrderValue1( this.root, k);
}
private T getOrderValue(BSTNode<T> root) {
if(root==null){
return null;
}
T val=getOrderValue(root.getRight());
if(val!=null){
return val;
}
if(k--==1) {
return root.getData();
}
return getOrderValue(root.getLeft());
}
private int i=1;
private T getOrderValue1(BSTNode<T> root,int k){
if(root==null){
return null;
}
T val=getOrderValue1(root.getLeft(),k);
if(val!=null)
return val;
if(i++==k){
return root.getData();
}
return getOrderValue1(root.getRight(),k);
}
public void rebuild(T[] pre,T[] in){
this.root=rebuild(pre,0,pre.length-1,in,0,in.length-1);
}
private BSTNode<T> rebuild(T[] pre, int i, int j, T[] in, int m, int n) {
if(i>j||m>n)
return null;
//前序数组当前第一个结点为当前树的root结点。
BSTNode<T> tmp=new BSTNode<>(pre[i],null,null);
//中序遍历,找到当前子树根结点
for(int k=m;k<=n;k++){
if(in[k].compareTo(pre[i])==0){
//当在中序遍历中找到当前根节点时,中序m--k之间为其左子树中序,k--n为其右子树中序
//对于左子树来说,前序的(k-m)个结点为其左子树前序结点,剩余的为其右子树结点
tmp.setLeft(rebuild(pre,i+1,i+(k-m),in,m,k-1));
tmp.setRight(rebuild(pre,i+(k-m)+1,j,in,k+1,n));
return tmp;
}
}
return tmp; //走到这,说明中序没有找到。
}
/*
* @Description : 判断是不是子树
* 首先在主树中看能不能找到子树的根结点
* 在找到的情况下判断每个结点是否相等。
* @param null
* @return :
* @exception :
* @date : 2019/7/3 18:54
*/
public boolean isChildTree(BST<T> tree){
//找到当前树中与之匹配的根结点
BSTNode<T> tmp=non_query(tree.root.getData());
if(tmp!=null){ //找到进行比较
return isChildTree(tmp,tree.root);
}
return false; //没找到
}
private boolean isChildTree(BSTNode<T> father, BSTNode<T> child) {
if(father==null&&child==null)
return true;
if(father==null)
return false;
if(child==null)
return true;
if(father.getData().compareTo(child.getData())==0){
return isChildTree( father.getLeft(), child.getLeft())&&isChildTree( father.getRight(), child.getRight());
}
return false;
}
}
public class BSTDemo {
public static void main(String[] args) {
BST<Integer> bst = new BST();
int[] ar = {58,23,82,12,35,69,87,18,47,74,95};
for (int val : ar) {
bst.non_insert(val);
}
System.out.println(bst.level());
System.out.println(bst.number());
bst.preOrder();
bst.inOder();
bst.postOrder();
bst.levelOrder();
System.out.println();
System.out.println(bst.getOrderValue(3));
}
}
数据结构-BST树(镜像&前序&中序&后序&重构)
猜你喜欢
转载自blog.csdn.net/Fly_Fly_Zhang/article/details/94594010
今日推荐
周排行