二叉排序树的整理

1.二叉数的类设计

使用内部类,这个属性可以设置为private,如果是外部类,那么不能设计 为private,否则会多次使用set,get方法,很麻烦。

	class Node		//使用内部类
	{
		int data;
		private Node left,right;    
		public Node(int data)
		{
			this.data = data;
		}
	}

2.插入一个元素

插入二叉树有两种方式:第一种方式是传入指针的值,这时候需要返回头结点,

                                     第二种方式是传入指针的地址,这在C++里面的操作

自己的理解:因为Java中没有二级指针,所以如下面的例子中,root是根结点,开始为null,使用插入一个结点put(root,data),此时在子函数中put(Node x,int data)完成插入操作,此时是将Node x指向了新的结点,而root仍然为null,所以在Java中采用的办法是操作完成后,返回Node x,将其指向根结点,从而完成对树的操作。

	//插入
	public void put(int data)
	{
		root = put(root,data);		//对于根节点是要更新的,这里其实有点起到二级指针的作用    注意点1
	}
	public Node put(Node x ,int data)
	{
		if(x==null)
			return new Node(data);		
		else if(data>x.data)
		{
			x.right = put(x.right,data);
		}
		else if(data<x.data)
		{
			x.left = put(x.left,data);
		}
//		else					//这行代码不能加  注意点2
//		{
//			return null;
//		}
		return x;			        //这边的x的作用   注意点3
	}

注意点:在二叉树中已经包含某值,这时候不要多此一举return null,可以这样理解,否则直接返回null,那么该元素的孩子都会丢失了

3.查找某值是否存在

	public boolean get(Node x,int data)
	{
		if(x==null)
			return false;
		else if(x.data>data)
			
		{
			return get(x.left,data);
		}
		else if(x.data<data)	
		{
			return get(x.right,data);
		}
		else			//如果找到,就返回true
		{
			return true;
		}
	}

4.找出最小值

递归方式:

	public Node min(Node root){
		if(root.left==null) 
			return root;
		else
			return min(root.left);
	}
非递归方式:
	public Node min(Node x){
		while(x.left!=null){
			x = x.left;
		}
		return x;
	}

说明:这里找到最小值时直接返回,并不改变树的结构,所以不需要返回头指针,同理,对树的遍历,前序,中序和后序也不改变树的结构,所以也都不用返回根指针。

5.删除最小值

	public Node deleteMin(Node x)		
	{
		if(x.left==null)
			return x.right;
		x.left = deleteMin(x.left);
		return x;			
	}
删除后返回的是root指针

6.删除某一个值

基本思路:用需要删除结点的直接前驱或者直接后继来替代这个结点

	public Node delete(Node x,int data)
	{
		if(x==null)
			return null;
		if(x.data>data)
		{
			x.left = delete(x.left,data);
		}
		else if(x.data<data)
		{
			x.right = delete(x.right,data);
		}
		else
		{
			//如果只有左子结点或者只有右子结点
			if(x.left==null)            //如果被删除的结点只有右孩子
				return x.right;
			else if(x.right==null)      //如果被删除的结点只有左孩子
				return x.left;
			else                        //如果被删除的结点既有右孩子又有左孩子
			{
				Node t = x;
				x = min(t.right);
				x.right = deleteMin(t.right);
				x.left = t.left;
			}
		}
		return x;
	}

说明:

1)删除某个结点的时候,可以分为两种情况,一种是待删除的结点只有左孩子或者只有右孩子,第二种情况是待删除的结点既有左孩子又有右孩子。

2)如果既有左孩子又有右孩子,删除一个结点的基本思想——使用直接后驱或者直接前继来替代它

Node t = x;                      //指向待删除结点
x = min(t.right);                //找到直接后继
x.right = deleteMin(t.right);    //直接后继的右指针指向被删除结点的右指针
x.left = t.left;                 //直接后继的左指针指向被删除结点的左指针

这里特别注意的是deleteMin(t.right)这段代码,该函数返回t.right。

7.判断一个数组是不是二叉搜索树的后序遍历序列

代码示例:

	public static boolean verifySquenceOfBST(int[] a,int start,int end)
	{
		if(a==null)
			return false;
		int i;
		int temp = a[end];		//获取根结点的值
		for(i=start;i<end;i++)			//左子树结点的值小于根节点的值
		{
			if(a[i]>temp)	//这里要不要取等号
				break;
		}					//从start到i-1是左子树,从i到end是右子树
		int j = i;
		for(;j<end;j++)
		{
			if(a[j]<temp)
				return false;
		}
		
		boolean left = true;
		boolean right = true;
		if(i-1>start)		//****加上这个判断是为了说明还有左子树节点
		{
			left = verifySquenceOfBST(a, start, i-1);
		}
		if(i<=end-2)		//****加上这个判断是为了说明还有右子树节点
		{
			right = verifySquenceOfBST(a, i, end-1);
		}
		return left&&right;
	}

1)判别方法:后序遍历得到的序列中,最后一个数字是树的根节点的值,在二叉排序树中,根结点一定可以将数组分为两个连续的部分,一个连续的部分都小于根节点,另一个连续的部分都大于根结点。同理这两个连续的小部分又都满足上面的规律。

2)这里用到了分治法,将大问题变成小问题。

3)对比快速排序,这里面的思想是不是一样的。两者的区别,有没有返回值,没有返回值,直接在函数开头判断。

8.找二叉排序树中的第k大节点 

二叉排序树的中序遍历的值是单调递增的,也就是说,找二叉排序树的第k大结点,其实就是中序遍历的第k个被遍历的值,但是注意Java中无法操作地址,所以这里使用了一个数组来计算是第几个值。

第一种方法代码示例:

	public int searchNodeK1(int k){                
		int[] temp = {k};			//可以直接传入参数的
		return searchNodeK1(root,temp);
	}
	
	public int searchNodeK1(Node x,int[] k){

		if(x==null)
		return -1;				//如果没有找到就返回-1
		int k1 = searchNodeK1(x.left,k);
		k[0]--;
		if(k[0]==0){
			return x.data;		//找到那个元素就返回
		}

		int k2 = searchNodeK1(x.right, k);
		if(k1!=-1)
			return k1;
		
		if(k1!=-1)                //没有找到才返回-1
			return k1;
		else if(k2!=-1)           //没有找到才返回-1
			return k2;
		else
			return -1;
	}

说明:这里面的思想与求树的最大深度类似

第二种方法代码示例:

	public int searchNodeK2(int k){
		int[] temp = {k};			//可以直接传入参数的
		int[] result = {-1,-1};
		return searchNodeK2(root,temp,result);
	}
	
	public int searchNodeK2(Node x,int[] k,int[] result){

		//第二种方式  麻烦一点,将元素保存在数组中返回
		if(x==null)
			return -1;
		result[0] = searchNodeK2(x.left,k, result);
		k[0]--;
		if(k[0]==0){
			result[0] = x.data;
			return result[0];		//直接返回
		}
		System.out.println("result: "+result[1]++);
		if(result[0]==-1)
			result[0] = searchNodeK2(x.right, k,result);
		return result[0];
	}
小结: 对于二叉树或者二叉排序树,有几种基本结构,首先要判断是不是对树的结构有改变(增,删,改),如果是对树的结构有改变,那么一定要返回根结点,此时都会在函数末尾有return x样式,同时递归的调用也都是x.left = diGUi(x.left)样式,而如果不是树的结构有改变(只是查找),那么此时常见的是三层遍历的结构(不带返回值)和return diGUi(x.left)(带返回值)。

猜你喜欢

转载自blog.csdn.net/chenkaibsw/article/details/80059345