05 二分搜索树(BinarySearchTree)

  1 import java.util.LinkedList;
  2 import java.util.Queue;
  3 import java.util.Stack;
  4 
  5 /**
  6  * @author 阿遠
  7  * Date: 2019/4/30
  8  * Time: 15:23
  9  */
 10 public class BinarySearchTree<E extends Comparable<E>> {
 11 
 12     // 内部类定义节点
 13     private class Node{
 14         public E e;  // 节点值
 15         public Node left, right; // 左右节点
 16         // 构造函数
 17         public Node(E e) {
 18             this.e = e;
 19             this.left = null;
 20             this.right = null;
 21         }
 22     }
 23 
 24     private Node root; // 根节点
 25     private int size;  // 深度
 26 
 27     public  BinarySearchTree() {
 28         root = null;
 29         size = 0;
 30     }
 31 
 32     public int size() {
 33         return size;
 34     }
 35 
 36     public boolean isEmpty() {
 37          return size == 0;
 38     }
 39 
 40     // 向二分搜索树中添加新的元素e
 41 //    public void add(E e) {
 42 //        if (root == null) {
 43 //            root = new Node(e);
 44 //            size ++;
 45 //        } else {
 46 //            add(root, e);
 47 //        }
 48 //    }
 49     // 代码优化
 50     public void add(E e) {
 51         root = add(root, e);
 52     }
 53     // 向跟为node的二分搜索树种插入元素E,递归算法
 54 //    private void add(Node node, E e) {
 55 //        // 插入结束的条件
 56 //        if (e.equals(node.e)) { // 插入值与节点值相等
 57 //            return;
 58 //        } else if (e.compareTo(node.e) < 0 && node.left == null) {  // 插入值小于节点并且左子树为空
 59 //            node.left = new Node(e);
 60 //            size ++;
 61 //            return;
 62 //        } else if (e.compareTo(node.e) > 0 && node.right == null) { // 插入值大于节点并且右子树为空
 63 //            node.right = new Node(e);
 64 //            size ++;
 65 //            return;
 66 //        }
 67 //        // 递归插入
 68 //        if(e.compareTo(node.e) < 0) {
 69 //            add(node.left , e);
 70 //        } else {
 71 //            add(node.right, e);
 72 //        }
 73 //    }
 74     // add(Node node, E e) 代码优化: 返回插入新节点后的二分搜索树的根
 75     private Node add(Node node, E e) {
 76         if (node == null) {
 77             size ++;
 78             return new Node(e);
 79         }
 80         if (e.compareTo(node.e) < 0) {
 81             node.left = add(node.left, e);
 82         } else if (e.compareTo(node.e) > 0) {
 83             node.right = add(node.right, e);
 84         }
 85         return node;
 86     }
 87 
 88     // 看二分搜索树中是否包含元素e
 89     public boolean contains(E e) {
 90         return contains(root, e);
 91     }
 92     private boolean contains(Node node, E e) {
 93         if (node == null) {
 94             return false;
 95         }
 96         // 结束条件
 97         if (e.compareTo(node.e) == 0) {
 98             return true;
 99         }else if (e.compareTo(node.e) < 0) {  // 没有结束就递归
100             return contains(node.left, e);
101         }else { //e.compareTo(node.e) > 0
102             return contains(node.right, e);
103         }
104     }
105 
106     // 寻找二分搜索树的最小值
107     public E minimum() {
108         if (size == 0)
109             throw new IllegalArgumentException("BinarySearchTree is Empty");
110         return minimum(root).e;
111     }
112     private Node minimum(Node node) {
113         if (node.left == null)
114             return node;
115         return minimum(node.left);
116     }
117 
118     // 寻找二分搜索树的最大值
119     public E maxmum() {
120         if (size == 0)
121             throw new IllegalArgumentException("BinarySearchTree is Empty");
122         return maxmum(root).e;
123     }
124     private Node maxmum(Node node) {
125         if (node.right == null)
126             return node;
127         return maxmum(node.right);
128     }
129 
130     // 从二分搜索树中删除最小值所在节点,返回最小值
131     public E removeMin() {
132         E ret = minimum();
133         removeMin(root);
134         return ret;
135     }
136     // 删除掉以node为根的二分搜索树中的最小节点
137     // 返回删除节点后新的二分搜索树的根
138     private Node removeMin(Node node)  {
139         if (node.left == null) {
140             Node rightNode = node.right;
141             node.right = null;
142             size --;
143             return rightNode;
144         }
145         node.left = removeMin(node.left);
146         return node;
147     }
148 
149     // 从二分搜索树中删除最大值所在节点,返回最大值
150     public E removeMax() {
151         E ret = maxmum();
152         removeMax(root);
153         return ret;
154     }
155     // 删除掉以node为根的二分搜索树中的最小节点
156     // 返回删除节点后新的二分搜索树的根
157     private Node removeMax(Node node)  {
158         if (node.right == null) {
159             Node leftNode = node.left;
160             node.left = null;
161             size --;
162             return leftNode;
163         }
164         node.right = removeMax(node.right);
165         return node;
166     }
167 
168     // 从二分搜索树中删除元素为e节点
169     public void remove(E e) {
170         remove(root, e);
171     }
172     private Node remove(Node node, E e) {
173         if (node == null)  // 如果二分搜索树为空
174             return null;
175         if (e.compareTo(node.e) < 0) {
176             node.left = remove(node.left,e);
177             return node;
178         } else if (e.compareTo(node.e) > 0) {
179             node.right = remove(node.right, e);
180             return node;
181         }else {  // e == node.e
182             // 待删除左子树为空的情况
183             if (node.left == null) {
184                 Node rightNode = node.left;
185                 node.right = null;
186                 size --;
187                 return rightNode;
188             }
189             // 待删除右子树为空的情况
190             if (node.right == null) {
191                 Node leftNode = node.left;
192                 node.left = null;
193                 size --;
194                 return leftNode;
195             }
196             // 待删除节点左右子树均不为空的情况
197             // 找到比待删除节点大的最小节点,即将删除节点右子树的最小节点
198             // 用这个节点顶替待删除节点的位置
199             // 该方法的核心代码
200             Node successor = minimum(node.right);  // 后继
201             successor.right = removeMax(node.right);  // removeMax的作用是将node.right右子树的最小值删除
202             successor.left = node.left;
203             node.left = node.right = null;
204             return successor;
205         }
206     }
207 
208     // 二分搜索树递归前序遍历
209     public void preOrder() {
210         preOrder(root);
211     }
212     private void preOrder(Node node) {
213         // 递归终止条件
214         if (node == null) {
215             return;
216         }
217         // 对递归元素进行操作
218         System.out.println(node.e);
219         // 没有结束就递归
220         preOrder(node.left);
221         preOrder(node.right);
222     }
223 
224     // 二叉搜索树的非递归前序遍历
225     public void preOrderNR() {
226 
227         Stack<Node> stack = new Stack<>();
228         stack.push(root);
229         while (!stack.isEmpty()) {
230             Node cur = stack.pop();
231             System.out.println(cur.e);
232             if (cur.right != null) {
233                 stack.push(cur.right);
234             }
235             if (cur.left != null) {
236                 stack.push(cur.left);
237             }
238         }
239     }
240 
241     // 二分搜索树的中序遍历
242     public void inOrder() {
243         inOrder(root);
244     }
245     // 中序遍历以node为根的二分搜索树,递归算法  二分搜索树的中序遍历就是元素从小到大排序后的结果
246     private void inOrder(Node node) {
247         if (node == null) {
248             return;
249         }
250         inOrder(node.left);
251         System.out.println(node.e);
252         inOrder(node.right);
253     }
254 
255     // 二分搜索树的后序遍历
256     public void postOrder() {
257         postOrder(root);
258     }
259     // 后序遍历以node为根的二分搜索树,递归算法
260     private void postOrder(Node node) {
261         if (node == null) {
262             return;
263         }
264         postOrder(node.left);
265         postOrder(node.right);
266         System.out.println(node.e);
267     }
268 
269     // 前面实现的前中后三种遍历本质上都是深度优先的遍历,下面介绍层序遍历,以层为优先的遍历
270     // 层序遍历:一层一层的遍历
271     public void levelOrder() {
272         Queue<Node> q = new LinkedList<>();  // Queue在java中是一个借口,需使用具体的类(LinkedList)进行实现
273         q.add(root);
274         while (!q.isEmpty()) {
275             Node cur = q.remove();
276             System.out.println(cur.e);
277 
278             if (cur.left != null)
279                 q.add(cur.left);
280             if (cur.right != null)
281                 q.add(cur.right);
282         }
283     }
284 
285     @Override
286     public String toString() {
287         StringBuilder res = new StringBuilder();
288         generateBSTString(root, 0, res);
289         return res.toString();
290     }
291     // 生成以node为根节点,深度为depth的描述二叉树的字符串
292     private void generateBSTString(Node node, int depth, StringBuilder res) {
293         if (node == null) {
294             res.append(generateDepthString(depth) + node.e + "null
");
295             return;
296         }
297         res.append(generateDepthString(depth) + node.e + "null
");
298         generateBSTString(node.left, depth + 1, res);
299         generateBSTString(node.right, depth + 1, res);
300     }
301 
302     private String generateDepthString(int depth) {
303         StringBuilder res = new StringBuilder();
304         for (int i = 0; i < depth; i ++) {
305             res.append("--");
306         }
307         return res.toString();
308     }
309 }
原文地址:https://www.cnblogs.com/a-yuan/p/10800586.html