• 二叉查找树BST----java实现


                                                                    二叉查找树BST----java实现

    1.二叉查找树简单介绍

    二叉查找树又名二叉搜索树和二叉排序树。性质例如以下:

     

    在二叉查找树中:
    (01) 若随意节点的左子树不空,则左子树上全部结点的值均小于它的根结点的值。
    (02) 随意节点的右子树不空,则右子树上全部结点的值均大于它的根结点的值;
    (03) 随意节点的左、右子树也分别为二叉查找树。


    (04) 没有键值相等的节点(no duplicate nodes)。

    2.二叉查找树节点类

    class TreeNode
    {
    	int value;
    	TreeNode parent;
    	TreeNode left;
    	TreeNode right;
    	public TreeNode(int value, TreeNode parent, TreeNode left, TreeNode right) {
    		this.value = value;
    		this.parent = parent;
    		this.left = left;
    		this.right = right;
    	}	 
    }

    3.遍历

       二叉查找树的遍历同二叉树的遍历,递归与非递归方法详见二叉树的递归遍历和非递归遍历(附具体样例)

    4.最大和最小值

    a.BST中的最小值即最左的孩子。

    //求BST的最小值
    	public TreeNode  getMin(TreeNode root)
    	{
    		if(root==null)
    			return null;
    		while(root.left!=null)
    			root=root.left;	 
    		return root;
    	}

    b.BST中的最大值即最右的孩子。

    //求BST的最大值
    		public TreeNode  getMax(TreeNode root)
    		{
    			if(root==null)
    				return null;
    			while(root.right!=null)
    				root=root.right;
    			return root;
    		}

    5.前驱和后继节点


    ps:图片来于网络

    a.BST中某节点前驱节点==小于该节点的全部节点中的最大值

    前驱easy情形:5寻前驱 4

    前驱复杂情形:11寻前驱 10

    //查找BST中某节点的前驱节点.即查找数据值小于该结点的最大结点。
    		public TreeNode preNode(TreeNode x)
    		{
    			if(x==null)
    				return null;
    			// 假设x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。

    if(x.left!=null) return getMax(x.left); // 假设x没有左孩子。

    则x有下面两种可能: // (01) x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。 // (02) x是"一个左孩子",则 前驱节点为x的某一个祖先节点的父节点,并且该祖先节点是作为其父节点的右儿子 TreeNode p=x.parent; while(p!=null&&p.left==x) { x=p;//父节点置为新的x p=p.parent; //父节点的父节点置为新的父节点 } return p; }

    b.BST中某节点后继节点==大于该节点的全部节点中的最小值

    后继easy情形:5寻后继 6

    复杂情形:9寻后继 10

     

    //查找BST中某节点的后继节点.即查找数据值大于该结点的最小结点。

    public TreeNode postNode(TreeNode x) { if(x==null) return null; // 假设x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。 if(x.left!=null) return getMin(x.right); // 假设x没有右孩子。则x有下面两种可能: // (01) x是"一个左孩子",则"x的后继结点"为 "它的父结点"。 // (02) x是"一个右孩子",则 前驱节点为x的某一个祖先节点的父节点,并且该祖先节点是作为其父节点的左儿子 TreeNode p=x.parent; while(p!=null&&p.right==x) { x=p;//父节点置为新的x p=p.parent; //父节点的父节点置为新的父节点 } return p; }


    6.查找

    查找值为val的节点,假设小于根节点在左子树查找,反之在右子树查找

    //查找值为val的节点  --递归版--
    		public TreeNode searchRec(TreeNode root ,int val)
    		{
    			if(root==null)
    				return root;
    			if(val<root.value)
    				return searchRec(root.left,val);
    			else if(val>root.value)
    				return searchRec(root.right,val);
    			else
    				return root;
    		}
    		//查找值为val的节点  --非 递归版--
    		public TreeNode search(TreeNode root ,int val)
    		{
    			if(root==null)
    				return root;
    			while(root!=null)
    			{
    				if(val<root.value)
    					root=root.left;
    				else if(val>root.value)
    					root=root.right;
    				else
    					return root;
    			}
    			return root;
    		}		 

    7.插入

    a.若当前的二叉查找树为空,则插入的元素为根节点 

    b.若插入的元素值小于根节点值。则将元素插入到左子树中

    c.若插入的元素值不小于根节点值,则将元素插入到右子树中。首先找到插入的位置,要么向左,要么向右,直到找到空结点,即为插入位置,假设找到了同样值的结点,插入失败。

     

    //BST插入节点  --递归版--
    		public TreeNode insertRec(TreeNode root,TreeNode x)
    		{
    			if(root==null)
    				root=x;
    			else if(x.value<root.value)
    				root.left=insertRec(root.left,  x);
    			else if(x.value>root.value)
    				root.right=insertRec(root.right,  x);
    			return root;
    		}
    		//BST插入节点  --非 递归版--
    		public TreeNode insert(TreeNode root,TreeNode x)
    		{
    			if(root==null)
    				root=x;
    			TreeNode p=null;//须要记录父节点
    			while(root!=null)//定位插入的位置
    			{
    				p=root;//记录父节点
    				if(x.value<root.value)
    					root=root.left;
    				else
    					root=root.right;
    			}
    			x.parent=p;//定位到合适的页节点的空白处后。依据和父节点的大小比較插入合适的位置
    			if(x.value<p.value) 
    				p.left=x;
    			else if(x.value>p.value)
    				p.right=x;
    			return root;
    		}

    8.删除

    二叉查找树的删除,分三种情况进行处理:
    1.p为叶子节点。直接删除该节点,再改动其父节点的指针(注意分是根节点和不是根节点),如图a。
    2.p为单支节点(即仅仅有左子树或右子树)。

    让p的子树与p的父亲节点相连,删除p就可以。(注意分是根节点和不是根节点);如图b。


    3.有两个孩子的情况,当前结点与左子树中最大的元素交换。然后删除当前结点。左子树最大的元素一定是叶子结点,交换后。当前结点即为叶子结点。删除參考没有孩子的情况。还有一种方法是,当前结点与右子树中最小的元素交换,然后删除当前结点。如图c。



    ps:图片来于网络


    //BST删除节点
    		public void delete(TreeNode root,TreeNode x)
    		{
    			if(root==null)
    				return ;
    			TreeNode p=null;
    			while(root!=null)//定位到须要删除的节点
    			{
    				if(x.value<root.value)
    				{
    					p=root;//记录父节点
    					root=root.left;
    				}
    				else if(x.value>root.value)
    				{
    					p=root;//记录父节点
    					root=root.right;
    				}
    				else//找到啦
    				{
    					if(root.left==null&&root.right==null)//①待删除的是 叶子节点
    					{
    						if(p==null)//待删除的是根节点
    							root=null;
    						else
    						{
    							if(p.left==root)
    								p.left=null;
    							else if(p.right==root)
    								p.right=null;
    						}
    					}
    					else if(root.left!=null&&root.right==null)//② 待删除的节点仅仅有左孩子
    					{
    						if(p==null)//待删除的是根节点
    							root=root.left;
    						else
    						{
    							 if(p.left==root)//待删除的本身是一个左孩子
    								 p.left=root.left;
    							 else if(p.right==root)
    								 p.right=root.left;
    						}
    					}
    					else if(root.left==null&&root.right!=null)//② 待删除的节点仅仅有右孩子
    					{
    						if(p==null)//待删除的是根节点
    							root=root.right;
    						else
    						{
     							 if(p.left==root)//待删除的本身是一个左孩子
     								 p.left=root.right;
     							 else if(p.right==root)
     								 p.right=root.right;
     							 
    						}
    					}
    					else//③待删除的节点即有左孩子又有右孩子    方法:得到待删除节点右子树的最小值。    
    					{//该最小值与待删除节点进行“ 值 ”交换。删除该最小值位置处的节点
    						TreeNode rMin=root.right; //求待删除节点的后继节点,即待删除节点的右孩子的最小值(找到的后继节点肯定没有左孩子!!。)
    						TreeNode rMinP=null;//由于须要删除后继节点位置,所以须要记录父节点
    						while(rMin!=null)
    						{
    							rMinP=rMin;
    							rMin=rMin.left;
    						}
    						 int rootVtemp=root.value;//值交换
    						 root.value=rMin.value;
    						 rMin.value=rootVtemp;
    						 //删除rMin位置的节点,此时此位置的值已是待删节点的值
    						 if(rMinP.left==rMin)
    							 rMinP.left=rMin.right;
    						 else if(rMinP.right==rMin)
    							 rMinP.right=rMin.right;
    					}
    				}
    				break;//找到后删了后就跳出while循环
    			}
    			 
    		}

    9.二叉树查找树常见面试题

    a.推断一个数组是不是二叉搜索树的后序遍历

    package com.sheepmu;
    
    public class Offer24 
    {
    	public static void main(String[] args)
    	{
    		int[] a={5,7,6,9,11,10,8};
    		int len=a.length;
    	 
    		System.out.println(isProOfBST(a,len));
    	}
    	public static boolean isProOfBST(int[] a,int len) 
    	{
    		if(a==null||len<=0)
    			return false;
    		int root=a[len-1];//后序遍历的最后一个为根节点
    		int i=0;
    		while(a[i]<root)//找到左树的个数
    			i++;
    		int j=i;//先看右树中是否有非法数字,即比根节点小的数字
    		while(j<len-1)
    		{
    			if(a[j]<root)
    				return false;
    			j++;
    		}
    		//若左右子树的数字都合法,即左子树都比根的值小,右子树都比根节点大;此时仅仅需递归推断左右子树是否是二叉搜索树的后序遍历
    		//求左右子树的数组,到这儿明显发现用字符串非常爽呀直接subString()
    		boolean left=true;
    		if(i>0)//必需要推断是否存在左树
    		{
    			int[] aleft=new int[i];
    			for(int x=0;x<i;x++) 
    				aleft[x]=a[x];
    			  left=isProOfBST(aleft,i);
    		}
    		boolean right=true;
    		if(i<len-1)//必需要推断是否存在右树
    		{
    			int[] aright=new int[len-i-1];
    //			for(int y=i;y<len-1;y++)//粗心啊!!。!

    // { // aright[y]=a[y]; // } for(int y=0;y<len-i-1;y++) aright[y]=a[i+y]; right=isProOfBST(aright,len-i-1); } return left&&right; } }

    b.将一颗二叉搜索树转为为排序的双向链表



  • 相关阅读:
    redis 源码阅读 数值转字符 longlong2str
    redis 源码阅读 内部数据结构--字符串
    redis 查看的版本
    redis 配置
    redis 基础
    redis 安装
    git 中关于LF 和 CRLF 的问题
    git 常用命令
    linux svn 服务端搭建
    测试开发之Django——No8.Django中的视图与URL配置
  • 原文地址:https://www.cnblogs.com/gccbuaa/p/6785621.html
Copyright © 2020-2023  润新知