二叉排序树(二叉搜索树)

二叉排序树

二叉排序树又称为二叉查找树,它是一种特殊结构的二叉树,其定义为:二叉树排序树或者是一棵空树,或者是具有如下性质的二叉树:

(1)若它的左子树非空,则左子树上所有结点的值均小于根结点的值;

(2)若它的右子树非空,则右子树上所有结点的值均大于根结点的值;

(3)它的左右子树也分别为二叉排序树。

这是一个递归定义。由定义可以得出二叉排序树的一个重要性质:中序遍历一个二叉排序树时可以得到一个递增有序序列。图1所示的二叉树就是一棵二叉排序树,若中序遍历图8.3(a)的二叉排序树,则可得到一个递增有序序列为:1,2,3,4,5,6,7,8,9。

    


                         (a) 二叉排序树示例1                               (b) 二叉排序树示例2(根据字符ASCII码的大小)

                                                                                     

                                                      图1二叉排序树

在下面讨论二叉排序树的操作中,使用二叉链表作为存储结构,其结点结构说明如下:

typedef struct node

{ KeyType key ; /*关键字的值*/

struct node *lchild,*rchild;/*左右指针*/

}bstnode,*BSTree;

1.二叉排序树的插入和生成

已知一个关键字值为key的结点s,若将其插入到二叉排序树中,只要保证插入后仍符合二叉排序树的定义即可。插入可以用下面的方法进行:1)若二叉树序树是空树,则key成为二叉树序树的根;2)若二叉树序树非空,则将key与二叉树序树的根进行比较,如果key的值等于根结点的值,则停止插入,如果key的值小于根结点的值,则将key插入左子树,如果key的值大于根结点的值,则将key插入右子树。

例如,设关键字的输入顺序为:45,24 ,53,12,28,90,按上述算法生成的二叉排序树的过程如图2所示。


 

 

图2 二叉排序树的建立过程

对同样一些元素值,如果输入顺序不同,所创建的二叉树形态也不同。如上面的例子如果输入顺序为 24,53,90,12,28,45,则生成的二叉排序树如图3所示:

 

 

图3输入顺序不同所建立的不同二叉排序树

 2.二叉排序树的查找过程


  由其定义可见,二叉排序树的查找过程为:
  (1)若查找树为空,查找失败。
  (2)查找树非空,将给定值key与查找树的根结点关键码比较。
  (3)若相等,查找成功,结束查找过程,否则:
  ① 当给值key小于根结点关键码,查找将在以左孩子为根的子树上继续进行,转(1)。
  ② 当给值key大于根结点关键码,查找将在以右孩子为根的子树上继续进行,转(1)。


3.二叉排序树删除操作


  从二叉排序树中删除一个结点之后,要求其仍能保持二叉排序树的特性。
  设待删结点为*p(p为指向待删结点的指针),其双亲结点为*f,删除可以分三种情况,如图6-4所示。

 

  (1)*p结点为叶结点,由于删去叶结点后不影响整棵树的特性,所以,只需将被删结点的双亲结点相应指针域改为空指针,如图6-4(a)所示。
  (2)*p结点只有右子树或只有左子树,此时,只需将替换*f结点的*p子树即可,如图6-4(b)、(c)所示。
  (3)*p结点既有左子树又有右子树,可按中序遍历保持有序地进行调整,如图6-4(d)、(e)所示。

  设删除*p结点前,中序遍历序列为:
  ① P为F的左子女时有:…,Pi子树,P,Pj,S子树,Pk,Sk子树,…,P2,S2子树,P1,S1子树,F,…。
  ② P为F的右子女时有:…,F,Pi子树,P,Pj,S子树,Pk,Sk子树,…,P2,S2子树,P1,S1子树,…。
  则删除*p结点后,中序遍历序列应为:
  ① P为F的左子女时有:…,Pi子树,Pj,S子树,Pk,Sk子树,…,P2,S2子树,P1,S1子树,F,…。
  ② P为F的右子女时有:…,F,Pi子树,Pj,S子树,Pk,Sk子树,…,P2,S2子树,P1,S1子树,…。
  有两种调整方法:
  ① 直接令Pi为*f相应的子树,以Pr为Pi中序遍历的最后一个结点Pk的右子树。
  ② 令*p结点的直接前驱Pr或直接后继(对Pi子树中序遍历的最后一个结点Pk)替换*p结点,再按(2)的方法删去Pr或Pk。
  【算法分析】
  对给定序列建立二叉排序树,若左右子树均匀分布,则其查找过程类似于有序表的折半查找。但若给定序列原本有序,则建立的二叉排序树就蜕化为单链表,其查找效率和顺序查找一样。因此,对均匀的二叉排序树进行插入或删除结点后,应进行调整,使其依然保持均匀。

程序代码实现:

package binarytree;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;

public class BinarySortTree<T extends Comparable<T>> {
	//二叉搜索树,二叉排序树
	public class Node{
		T data;
		Node parent;
		Node lchild;
		Node rchild;
		public Node(T data,Node parent,Node lchild,Node rchild){
			this.data=data;
			this.parent=parent;
			this.lchild=lchild;
			this.rchild=rchild;
		}
		public boolean equals(Object obj){
			if (this==obj) {
				return true;
			}
			if (obj.getClass()==Node.class) {
				Node target=(Node)obj;
				return data.equals(target.data)&&
						lchild==target.lchild&&
						rchild==target.rchild&&
						parent==target.parent;
			}
			return false;
		}
		@Override
		public String toString() {
			return "Node [data="+data+"]";
		}
		
	}
	
	private Node root;

	public BinarySortTree() {
		root=null;
	}
	public BinarySortTree(T t) {
		this.root = new Node(t, null, null, null);
	}
	//添加节点
	public void add(T element){
		if (root==null) {
			root=new Node(element, null, null, null);
		} else {
			Node current=root;
			Node parent=null;
			int cmp=0;
			//搜索合适的叶子节点,以该叶子节点为父节点添加新节点
			do {
				parent=current;
				cmp=element.compareTo(current.data);
				if (cmp>0) {
					current=current.rchild;
				} else {
					current=current.lchild;
				}
			} while (current!=null);
			//创建新节点
			Node newNode=new Node(element, parent, null, null);
			if (cmp>0) {
				parent.rchild=newNode;
			} else {
				parent.lchild=newNode;
			}
		}
	}
	//删除节点
	public void remove(T element){
		//获取要删除的节点
		Node target=getNode(element);
		if (target==null) {
			return;
		}
		//左、右子树是否为空
		if (target.lchild==null&&target.rchild==null) {
			if (target==root) {
				root=null;
			} else {
				if (target==target.parent.lchild) {
					target.parent.lchild=null;
				} else {
					target.parent.rchild=null;
				}
				target.parent=null;
			}
		} else if(target.lchild==null&&target.rchild!=null){
			if (target==root) {
				root=target.rchild;
			} else {
				if (target==target.parent.lchild) {
					target.parent.lchild=target.rchild;
				} else {
					target.parent.rchild=target.rchild;
				}
				target.rchild.parent=target.parent;
			}
		}else if(target.lchild!=null&&target.rchild==null){
			if (target==root) {
				root=target.lchild;
			} else {
				if (target==target.parent.lchild) {
					target.parent.lchild=target.lchild;
				} else {
					target.parent.rchild=target.lchild;
				}
				target.lchild.parent=target.parent;
			}
		}else {
			Node lchildMaxNode=target.lchild;//存放左孩子最大的节点
			while (lchildMaxNode.rchild!=null) {
				lchildMaxNode=lchildMaxNode.rchild;
			}
			lchildMaxNode.parent.rchild=null;
			lchildMaxNode.parent=target.parent;
			
			if (target==target.parent.lchild) {
				target.parent.lchild=lchildMaxNode;
			} else {
				target.parent.rchild=lchildMaxNode;
			}
			lchildMaxNode.lchild=target.lchild;
			lchildMaxNode.rchild=target.rchild;
			target.parent=target.lchild=target.rchild=null;
		}
	}
	//获取要指定的节点
	public Node getNode(T element) {
		Node p=root;
		while (p!=null) {
			int cmp=element.compareTo(p.data);
			if (cmp>0) {
				p=p.rchild;
			} else if (cmp<0) {
				p=p.lchild;
			}else {
				return p;
			}
		}
		return null;
	}
	//广度优先遍历
	public List<Node> breadthFrist(){
		Queue<Node> queue=new ArrayDeque<Node>();
		List<Node> list=new ArrayList<Node>();
		if (root!=null) {
			queue.offer(root);
		}
		while (!queue.isEmpty()) {
			list.add(queue.peek());
			Node pNode=queue.poll();
			if (pNode.lchild!=null) {
				queue.offer(pNode.lchild);
			}
			if (pNode.rchild!=null) {
				queue.offer(pNode.rchild);
			}
		}
		return list;
	}
}


 

转载于:https://www.cnblogs.com/jiutianhe/archive/2012/10/09/2755652.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值