二叉排序树
二叉排序树又称为二叉查找树,它是一种特殊结构的二叉树,其定义为:二叉树排序树或者是一棵空树,或者是具有如下性质的二叉树:
(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;
- }
- }