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

                                                                二叉查找树BST—-java实现

1.二叉查找树简介

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

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

在二叉查找树中:
(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.前驱和后继节点

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

ps:图片来于网络

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

前驱容易情形: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中某节点后继节点==大于该节点的所有节点中的最小值

后继容易情形: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。

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

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.将一颗二叉搜索树转为为排序的双向链表

    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/sheepmu/article/details/38407221
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞