二叉排序树

  当用线性表作为表的组织形式时,可以有三种查找法。其中以二分查找效率最高。但由于二分查找要求表中

节点按关键字有序,且不能用链表作存储结构,因此,当表的插入或删除操作频繁时,为维护表的有序性,

势必要移动表中很多节点。这时由移动节点引起的额外时间开销,就会抵消二分查找的优点。也就是说,

二分查找只适用于静态查找表。

  若要对动态查找表进行高效率的查找,可采用下面介绍的几种特殊的二叉树或树作为表的组织形式。不妨将它们统称为树表。

 

二叉排序树

1、二叉排序树的定义
 
 
 二叉排序树(Binary Sort Tree)又称二叉查找(搜索)树(Binary Search Tree)。其定义为:二叉排序树或者是空树,或者是满足如下性质的二叉树:
①若它的左子树非空,则左子树上所有结点的值均小于根结点的值;
②若它的右子树非空,则右子树上所有结点的值均大于根结点的值;
③左、右子树本身又各是一棵二叉排序树。
  上述性质简称二叉排序树性质(BST性质),故二叉排序树实际上是满足BST性质的二叉树。

2、二叉排序树的特点
  
由BST性质可得:
  (1) 二叉排序树中任一结点x,其左(右)子树中任一结点y(若存在)的关键字必小(大)于x的关键字。
  (2) 二叉排序树中,各结点关键字是惟一的。
  注意:
  实际应用中,不能保证被查找的数据集中各元素的关键字互不相同,所以可将二叉排序树定义中BST性质(1)里的"小于"改为"大于等于",或将BST性质(2)里的"大于"改为"小于等于",甚至可同时修改这两个性质。
  (3) 按中序遍历该树所得到的中序序列是一个递增有序序列。

 


 java版源代码:

  1 package arrange;
  2 
  3 public class BinarySortTree {
  4     BSTreeNode rootNode;// 创建根节点
  5     // 创建二叉查找树
  6 
  7     public void createBSTree(int[] A) {
  8         rootNode = new BSTreeNode(A[0], null, null);// 初始化根节点
  9 
 10         for (int i = 1; i < A.length; i++) {// 逐个取出数组A中的元素用来构造二叉查找树
 11             BSTreeNode tmpNode = rootNode; // 为什么rootNode每次循环后都能增加新的值 ?
 12             // System.out.println(tmpNode.data);
 13             while (true) {
 14                 if (tmpNode.data >= A[i]) {// 小于等于根节点
 15                     if (tmpNode.left == null) {// 如果左孩子为空,这把当前数组元素插入到左孩子节点的位置
 16                         tmpNode.left = new BSTreeNode(A[i], null, null); // 给节点的左子树赋值
 17                         break;
 18                     }
 19 
 20                     tmpNode = tmpNode.left;
 21                     // 如果不为空的话,则把左孩子节点用来和当前数组元素作比较
 22                 } else {// 大于根节点
 23                     if (tmpNode.right == null) {// 如果右孩子为空,这把当前数组元素插入到左孩子节点的位置
 24                         tmpNode.right = new BSTreeNode(A[i], null, null);
 25                         break;
 26                     }
 27                     tmpNode = tmpNode.right;// 如果不为空的话,则把右孩子节点用来和当前数组元素作比较
 28                 }
 29             }
 30         }
 31 
 32     }
 33 
 34     // 中序遍历二叉查找树(中序遍历之后便可以排序成功)
 35     public void inOrderBSTree(BSTreeNode x) {
 36         if (x != null) {
 37             inOrderBSTree(x.left);// 先遍历左子树
 38             System.out.print(x.data + ",");// 打印中间节点
 39             inOrderBSTree(x.right);// 最后遍历右子树
 40         }
 41     }
 42 
 43     // 查询二叉排序树--递归算法
 44     public BSTreeNode searchBSTree1(BSTreeNode x, BSTreeNode k) {
 45         if (x == null || k.data == x.data) {
 46             return x;// 返回查询到的节点
 47         }
 48         if (k.data < x.data) {// 如果k小于当前节点的数据域
 49             return searchBSTree1(x.left, k);// 从左孩子节点继续遍历
 50         } else {// 如果k大于当前节点的数据域
 51             return searchBSTree1(x.right, k);// 从右孩子节点继续遍历
 52         }
 53     }
 54 
 55     // 查询二叉排序树--非递归算法
 56     public BSTreeNode searchBSTree2(BSTreeNode x, BSTreeNode k) {
 57         while (x != null && k.data != x.data) {
 58             if (x.data > k.data) {
 59                 x = x.left;// 从左孩子节点继续遍历
 60             } else {
 61                 x = x.right;// 从右孩子节点继续遍历
 62             }
 63         }
 64         return x;
 65     }
 66 
 67     // 查找二叉查找树的最小节点
 68     public BSTreeNode searchMinNode(BSTreeNode x) {
 69         while (x.left != null) {
 70             x = x.left;
 71         }
 72         return x;
 73     }
 74 
 75     // 查找二叉查找树的最大节点
 76     public BSTreeNode searchMaxNode(BSTreeNode x) {
 77         while (x.right != null) {
 78             x = x.right;
 79         }
 80         return x;
 81     }
 82 
 83     // 插入节点进入二叉查找树
 84     public void insert(BSTreeNode k) {
 85         BSTreeNode r = rootNode;
 86         BSTreeNode p, q = null;
 87         p = r;
 88         while (p != null) {// while语句可以找到k节点所要插入的位置的父亲节点q
 89             q = p;
 90             if (p.data > k.data) {
 91                 p = p.left;
 92             } else {
 93                 p = p.right;
 94             }
 95         }
 96         if (q == null) {// 二叉查找树为空树的情况下,直接插入到根节点,这里的q为已知的k的父亲节点
 97             r.data = k.data;
 98         } else if (q.data > k.data) {// 插入到父亲节点q的左边
 99             q.left = k;
100         } else {// 插入到父亲节点q的右边
101             q.right = k;
102         }
103     }
104 
105     // 删除二叉查找树中指定的节点
106     public void delete(BSTreeNode k) {// 分三种情况删除
107         if (k.left == null && k.right == null) {// 第一种情况--没有子节点的情况下
108             BSTreeNode p = parent(k);
109             if (p.left == k) {// 其为父亲节点的左孩子
110                 p.left = null;
111             } else if (p.right == k) {// 其为父亲节点的右孩子
112                 p.right = null;
113             }
114         } else if (k.left != null && k.right != null) {// 第二种情况--有两个孩子节点的情况下
115             BSTreeNode s = successor(k);// k的后继节点
116             delete(s);
117             k.data = s.data;
118         } else {// 第三种情况--只有一个孩子节点的情况下
119             BSTreeNode p = parent(k);
120             if (p.left == k) {
121                 if (k.left != null) {
122                     p.left = k.left;
123                 } else {
124                     p.left = k.right;
125                 }
126             } else if (p.right == k) {
127                 if (k.left != null) {
128                     p.right = k.left;
129                 } else {
130                     p.right = k.right;
131                 }
132             }
133 
134         }
135     }
136 
137     // 查找节点的前驱节点
138     public BSTreeNode predecessor(BSTreeNode k) {
139         if (k.left != null) {
140             return searchMaxNode(k.left);// 左子树的最大值
141         }
142         BSTreeNode y = parent(k);
143         while (y != null && k == y.left) {// 向上找到最近的一个节点,其父亲节点的右子树包涵了当前节点或者其父亲节点为空
144             k = y;
145             y = parent(y);
146         }
147         return y;
148     }
149 
150     // 查找节点的后继节点
151     public BSTreeNode successor(BSTreeNode k) {
152         if (k.right != null) {
153             return searchMinNode(k.right);// 右子树的最小值
154         }
155         BSTreeNode y = parent(k);
156         while (y != null && k == y.right) {// 向上找到最近的一个节点,其父亲节点的左子树包涵了当前节点或者其父亲节点为空
157             k = y;
158             y = parent(y);
159         }
160         return y;
161     }
162 
163     // 求出父亲节点,在定义节点类BSTreeNode的时候,没有申明父亲节点,所以这里专门用parent用来输出父亲节点(主要是不想修改代码了,就在这里加一个parent函数吧)
164     public BSTreeNode parent(BSTreeNode k) {
165         BSTreeNode p = rootNode;
166         BSTreeNode tmp = null;
167         while (p != null && p.data != k.data) {// 最后的p为p。data等于k.data的节点,tmp为p的父亲节点
168             if (p.data > k.data) {
169                 tmp = p;// 临时存放父亲节点
170                 p = p.left;
171             } else {
172                 tmp = p;// 临时存放父亲节点
173                 p = p.right;
174             }
175         }
176         return tmp;
177     }
178 
179     /**
180      * @param args
181      */
182     public static void main(String[] args) {
183         // TODO Auto-generated method stub
184         int[] A = { 23, 12, 43, 2, 87, 54 };
185         BSTreeNode searchNode1 = null;// 递归查找到的结果
186         BSTreeNode searchNode2 = null;// 非递归查找到的结果
187         BSTreeNode searchMinNode = null;// 最小节点
188         BSTreeNode searchMaxNode = null;// 最大节点
189         BSTreeNode k = null, l = null, p = null, q = null, m = null, n = null;// 申明6个节点k,l,p,q,m,n
190 
191         System.out.print("打印出数组A中的元素");
192         for (int i = 0; i < A.length; i++)
193             System.out.print(A[i] + ",");
194 
195         BinarySortTree bsTree = new BinarySortTree();
196 
197         bsTree.createBSTree(A);// 创建二叉查找树
198 
199         System.out.println();
200         System.out.print("中序遍历构造的二叉查找树:");
201         bsTree.inOrderBSTree(bsTree.rootNode);// 中序遍历二叉查找树
202 
203         k = new BSTreeNode(23, null, null);// 初始化一节点k,左右孩子为null
204         l = new BSTreeNode(17, null, null);// 初始化一节点l,左右孩子为null
205         q = new BSTreeNode(12, null, null);// 初始化一节点q,左右孩子为null
206         // m=bsTree.searchBSTree2(bsTree.rootNode,
207         // k);//从二叉查找树里面查找一个节点,其m.data为k.data(这个m节点在后面用来测试程序)
208         searchNode1 = bsTree.searchBSTree1(bsTree.rootNode, k);// 查询二叉查找树----递归算法
209         searchNode2 = bsTree.searchBSTree2(bsTree.rootNode, k);// 查询二叉查找树----非递归算法
210         m = searchNode2;
211 
212         System.out.println("");
213         System.out.println("递归算法--查找节点域:" + searchNode1.data + "左孩子:" + searchNode1.left.data + "右孩子:" + "查找节点域:"
214                 + searchNode1.right.data);// 递归 实现
215         System.out.println("非递归算法--查找节点域:" + searchNode2.data + "左孩子:" + searchNode2.left.data + "右孩子:" + "查找节点域:"
216                 + searchNode2.right.data);// 循环实现
217 
218         searchMinNode = bsTree.searchMinNode(bsTree.rootNode);// 找到最小节点
219         searchMaxNode = bsTree.searchMaxNode(bsTree.rootNode);// 找到最大节点
220 
221         System.out.println("最小节点:" + searchMinNode.data);
222         System.out.println("最大节点:" + searchMaxNode.data);
223 
224         bsTree.insert(l);// 把l节点插入到二叉查找树中
225 
226         System.out.print("插入l节点(l的data为17)之后的二叉查找树的中序遍历结果:");
227         bsTree.inOrderBSTree(bsTree.rootNode);// 中序遍历二叉查找树
228 
229         p = bsTree.parent(q);// 取q节点的父亲节点
230 
231         System.out.println("");
232         System.out.println("q的父亲节点(q的data为12):" + p.data + "左孩子:" + p.left.data + "右孩子:" + "查找节点域:" + p.right.data);// 这里的左孩子或者右孩子节点可能打印为空,会出现null异常
233 
234         bsTree.delete(l);
235         System.out.print("删除l节点(l的data为17)之后的二叉查找树的中序遍历结果:");
236         bsTree.inOrderBSTree(bsTree.rootNode);// 中序遍历二叉查找树
237 
238         n = bsTree.successor(m);
239         System.out.println("");
240         System.out.println("K的后继节点(k的data为23):" + n.data);
241 
242         n = bsTree.predecessor(m);
243         System.out.println("K的前驱节点(k的data为23):" + n.data);
244     }
245 
246 }
247 
248 // 二叉查找树的节点类
249 class BSTreeNode {
250     int data;// 数据域
251     BSTreeNode right;// 左孩子
252     BSTreeNode left;// 右孩子
253     // 构造二叉查找树的节点
254 
255     public BSTreeNode(int data, BSTreeNode right, BSTreeNode left) {
256         this.data = data; // 给二叉树的数据域赋值
257         this.right = right; // 给该节点的右孩子赋值
258         this.left = left; // 给该节点的左孩子赋值
259     }
260 
261 }

 

 输出结果为:

 1 打印出数组A中的元素23,12,43,2,87,54,
 2 中序遍历构造的二叉查找树:2,12,23,43,54,87,
 3 递归算法--查找节点域:23左孩子:12右孩子:查找节点域:43
 4 非递归算法--查找节点域:23左孩子:12右孩子:查找节点域:43
 5 最小节点:2
 6 最大节点:87
 7 插入l节点(l的data为17)之后的二叉查找树的中序遍历结果:2,12,17,23,43,54,87,
 8 q的父亲节点(q的data为12):23左孩子:12右孩子:查找节点域:43
 9 删除l节点(l的data为17)之后的二叉查找树的中序遍历结果:2,12,23,43,54,87,
10 K的后继节点(k的data为23):43
11 K的前驱节点(k的data为23):12

 

posted @ 2016-04-18 10:50  笑哼  阅读(424)  评论(0编辑  收藏  举报