二分搜索树的深度优先遍历和广度优先遍历
二分搜索树的特点
二分搜索树首先是一个二叉树,其次其必须满足的条件是:每个节点的键值必须大于其左子节点,每个节点的键值必须小于其右子节点,这样以左右孩子为根的子树仍为二分搜索树,需要注意的是,二分搜索树不一定是一颗完全二叉树。
深度优先遍历
深度优先遍历的基本思想:对每一个可能的分支路径深入到不能再深入为止,而且每个结点只能访问一次。深度优先遍历的非递归的通用做法是采用栈。要特别注意的是,二分搜索树的深度优先遍历比较特殊,可以细分为前序遍历、中序遍历、后序遍历。
广度优先遍历
深度优先遍历的基本思想:从上往下对每一层依次访问,在每一层中,从左往右(也可以从右往左)访问结点,访问完一层就进入下一层,直到没有结点可以访问为止。广度优先遍历的非递归的通用做法是采用队列。
例如,对于上面的这个二分搜索树,其层序遍历(广度优先遍历)结果是:28 16 30 13 22 29 42。
Java代码实现深度优先遍历和广度优先遍历
下面采用Java语言来构建这个二分搜索树,并且实现前序遍历、中序遍历、后序遍历三种不同方式的深度优先遍历和广度优先遍历(层序遍历)。
1 package com.allSorts; 2 3 4 import java.util.LinkedList; 5 import java.util.Queue; 6 7 /** 8 * Created by Demrystv. 9 */ 10 public class BSTTraverseTest { 11 12 public static void main(String[] args) { 13 BinarySearchTree<Integer> tree = new BinarySearchTree<Integer>(); 14 tree.insertNode(28); 15 tree.insertNode(16); 16 tree.insertNode(13); 17 tree.insertNode(22); 18 tree.insertNode(30); 19 tree.insertNode(29); 20 tree.insertNode(42); 21 System.out.print("前序遍历(递归):"); 22 tree.preOrderTraverse(tree.getRoot()); 23 System.out.println(); 24 System.out.print("中序遍历(递归):"); 25 tree.inOrderTraverse(tree.getRoot()); 26 System.out.println(); 27 System.out.print("后序遍历(递归):"); 28 tree.postOrderTraverse(tree.getRoot()); 29 System.out.println(); 30 System.out.print("前序遍历(非递归):"); 31 tree.preOrderTraverseNoRecursion(tree.getRoot()); 32 System.out.println(); 33 System.out.print("中序遍历(非递归):"); 34 tree.inOrderTraverseNoRecursion(tree.getRoot()); 35 System.out.println(); 36 System.out.print("后序遍历(非递归):"); 37 tree.postOrderTraverseNoRecursion(tree.getRoot()); 38 System.out.println(); 39 System.out.print("广度优先遍历:"); 40 tree.breadthFirstTraverse(tree.getRoot()); 41 } 42 43 44 /** 45 * 结点 46 */ 47 public static class Node<E extends Comparable<E>> { 48 E value; 49 Node<E> left; 50 Node<E> right; 51 Node(E value) { 52 this.value = value; 53 left = null; 54 right = null; 55 } 56 } 57 58 /** 59 * 使用一个前序遍历构建一棵二分搜索树 60 */ 61 public static class BinarySearchTree<E extends Comparable<E>> { 62 private Node<E> root; 63 BinarySearchTree() { 64 root = null; 65 } 66 public void insertNode(E value) { 67 if (root == null) { 68 root = new Node<E>(value); 69 return; 70 } 71 Node<E> currentNode = root; 72 while (true) { 73 if (value.compareTo(currentNode.value) > 0) { 74 if (currentNode.right == null) { 75 currentNode.right = new Node<E>(value); 76 break; 77 } 78 currentNode = currentNode.right; 79 } else { 80 if (currentNode.left == null) { 81 currentNode.left = new Node<E>(value); 82 break; 83 } 84 currentNode = currentNode.left; 85 } 86 } 87 } 88 public Node<E> getRoot(){ 89 return root; 90 } 91 /** 92 * 前序遍历二分搜索树(递归) 93 * @param node 94 */ 95 public void preOrderTraverse(Node<E> node) { 96 System.out.print(node.value + " "); 97 if (node.left != null) 98 preOrderTraverse(node.left); 99 if (node.right != null) 100 preOrderTraverse(node.right); 101 } 102 /** 103 * 中序遍历二分搜索树(递归) 104 * @param node 105 */ 106 public void inOrderTraverse(Node<E> node) { 107 if (node.left != null) 108 inOrderTraverse(node.left); 109 System.out.print(node.value + " "); 110 if (node.right != null) 111 inOrderTraverse(node.right); 112 } 113 /** 114 * 后序遍历二分搜索树(递归) 115 * @param node 116 */ 117 public void postOrderTraverse(Node<E> node) { 118 if (node.left != null) 119 postOrderTraverse(node.left); 120 if (node.right != null) 121 postOrderTraverse(node.right); 122 System.out.print(node.value + " "); 123 } 124 /** 125 * 前序遍历二分搜索树(非递归),用的是栈 126 * @param root 127 */ 128 public void preOrderTraverseNoRecursion(Node<E> root) { 129 LinkedList<Node<E>> stack = new LinkedList<Node<E>>(); 130 Node<E> currentNode = null; 131 stack.push(root); 132 while (!stack.isEmpty()) { 133 currentNode = stack.pop(); 134 System.out.print(currentNode.value + " "); 135 if (currentNode.right != null) 136 stack.push(currentNode.right); 137 if (currentNode.left != null) 138 stack.push(currentNode.left); 139 } 140 } 141 /** 142 * 中序遍历二分搜索树(非递归),用的是栈 143 * @param root 144 */ 145 public void inOrderTraverseNoRecursion(Node<E> root) { 146 LinkedList<Node<E>> stack = new LinkedList<Node<E>>(); 147 Node<E> currentNode = root; 148 while (currentNode != null || !stack.isEmpty()) { 149 // 一直循环到二叉排序树最左端的叶子结点(currentNode是null) 150 while (currentNode != null) { 151 stack.push(currentNode); 152 currentNode = currentNode.left; 153 } 154 currentNode = stack.pop(); 155 System.out.print(currentNode.value + " "); 156 currentNode = currentNode.right; 157 } 158 } 159 /** 160 * 后序遍历二分搜索树(非递归),用的是栈 161 * @param root 162 */ 163 public void postOrderTraverseNoRecursion(Node<E> root) { 164 LinkedList<Node<E>> stack = new LinkedList<Node<E>>(); 165 Node<E> currentNode = root; 166 Node<E> rightNode = null; 167 while (currentNode != null || !stack.isEmpty()) { 168 // 一直循环到二叉排序树最左端的叶子结点(currentNode是null) 169 while (currentNode != null) { 170 stack.push(currentNode); 171 currentNode = currentNode.left; 172 } 173 currentNode = stack.pop(); 174 // 当前结点没有右结点或上一个结点(已经输出的结点)是当前结点的右结点,则输出当前结点 175 while (currentNode.right == null || currentNode.right == rightNode) { 176 System.out.print(currentNode.value + " "); 177 rightNode = currentNode; 178 if (stack.isEmpty()) { 179 return; //root以输出,则遍历结束 180 } 181 currentNode = stack.pop(); 182 } 183 stack.push(currentNode); //还有右结点没有遍历 184 currentNode = currentNode.right; 185 } 186 } 187 /** 188 * 广度优先遍历二分搜索树,又称层次遍历,用的是队列 189 * @param root 190 */ 191 public void breadthFirstTraverse(Node<E> root) { 192 Queue<Node<E>> queue = new LinkedList<Node<E>>(); 193 Node<E> currentNode = null; 194 queue.offer(root); 195 while (!queue.isEmpty()) { 196 currentNode = queue.poll(); 197 System.out.print(currentNode.value + " "); 198 if (currentNode.left != null) 199 queue.offer(currentNode.left); 200 if (currentNode.right != null) 201 queue.offer(currentNode.right); 202 } 203 } 204 } 205 }
运行结果如下,与前面理论分析完全对应。