当前位置:   article > 正文

BST 二叉搜索树_二叉搜索树查找算法压缩包

二叉搜索树查找算法压缩包

目录

一、BST概念

二、BST的查找、插入和遍历

1、查找

2、插入

3、遍历

(1)前序

(2)中序(递增显示)

(3)后序

(4)深度优先(DFS)

(5)广度优先(BFS)

4、删除

(1)无左子结点时

(2)有左子结点时

三、定义一个树接口

四、实现BST类 

五、数据压缩:哈夫曼编码


一、BST概念

前几天学习了堆排序,其实堆排序用到的结构就是二叉树。

那么BST是满足如下规则的二叉树:

树中的任意结点,左子树的值都小于结点的,右子树的值都大于结点的左小右大

二、BST的查找、插入和遍历

1、查找

遵循BST“左小右大”的原则,查询时从根结点向下依次查找各个子树,直到 子树为空 或 已查询到 为止。否则设置的对比current结点将一直与目标值比较,小于当前结点时赋给current.left,大于当前结点时赋给current.right。

2、插入

设置一个parent结点(新元素的父结点)和current结点(定位结点)。如果树为空,就使用新元素创造一个新的根结点。否则遍历寻找新元素结点的父结点的位置,接下来的操作就和“查找”操作很像了。定位父结点成功后比较新元素和父元素大小,判断标准依旧是左大右小。

3、遍历

树的遍历方法主要有前序(preorder)、中序(inorder)、后序(postorder)、深度优先和广度优先。以下面这个二叉树为例:

(1)前序

访问current -> 递归访问current.left -> 递归访问current.right

遍历为:60 55 45 57 59 100 67 107 101

(2)中序(递增显示)

递归访问current.left -> 访问current -> 递归访问current.right

遍历为:45 55 57 59 60 67 100 101 107(注意是先101才107 因为左边优先级大于右边)

(3)后序

递归访问current.left -> 递归访问current.right -> 访问current

遍历为:45 59 57 55 67 101 107 100 60

(4)深度优先(DFS)

访问root -> 任意顺序递归访问其left和right(前序遍历算是深度优先遍历的一个特例)

(5)广度优先(BFS)

逐层访问。访问root -> 从左往右访问其子结点 -> 再从左往右访问其孙结点2

遍历为:60 55 100 45 57 67 107 59 101

4、删除

删除操作要比插入操作复杂很多。删除结点之前需要定位current和current,然后分为有current.left和无current.left两个情况:

(1)无左子结点时

当current只有右子结点时,只需要:

  1. 将current.right和parent连接
  2. 删除current

(2)有左子结点时

找出current左子树中的最大元素记为rightMost(注意rightMost可能有左结点但绝对没有右结点),记rightMost的父结点为parentOfrightMost。接下来:

  1. 替换current中的元素值为rightMost
  2. 然后连接parentOfrightMost和rightMost.left
  3. 最后删除rightMost

三、定义一个树接口

我们定义Tree接口为Collection接口的子类:

  1. import java.util.Collection;
  2. public interface Tree<E> extends Collection<E> {
  3. public boolean search(E e);
  4. public boolean insert(E e);
  5. public boolean delete(E e);
  6. public int getSize();
  7. public default void inorder(){
  8. }
  9. public default void postorder(){
  10. }
  11. public default void preorder(){
  12. }
  13. // 重写Collection中定义的方法
  14. @Override
  15. public default boolean isEmpty(){
  16. return size() == 0;
  17. }
  18. @Override
  19. public default boolean contains(Object e){
  20. return search((E)e);
  21. }
  22. @Override
  23. public default boolean add(E e){
  24. return insert(e);
  25. }
  26. @Override
  27. public default boolean remove(Object e){
  28. return delete((E)e);
  29. }
  30. @Override
  31. public default int size(){
  32. return getSize();
  33. }
  34. @Override
  35. public default boolean containsAll(Collection<?> c){
  36. return false;
  37. }
  38. @Override
  39. public default boolean addAll(Collection<? extends E> c){
  40. return false;
  41. }
  42. @Override
  43. public default boolean removeAll(Collection<?> c){
  44. return false;
  45. }
  46. @Override
  47. public default boolean retainAll(Collection<?> c){
  48. return false;
  49. }
  50. @Override
  51. public default Object[] toArray(){
  52. return null;
  53. }
  54. @Override
  55. public default <T> T[] toArray(T[] array){
  56. return null;
  57. }
  58. }

四、实现BST类 

  1. class BST<E extends Comparable<E>> implements Tree<E>{
  2. protected TreeNode<E> root;
  3. protected int size = 0;
  4. public BST(){
  5. }
  6. public BST(E[] objects) {
  7. for(int i =0; i < objects.length; i++) {
  8. add(objects[i]);
  9. }
  10. }
  11. // 查找
  12. @Override
  13. public boolean search(E e){
  14. TreeNode current = root;
  15. while(current != null){ //不为空时->
  16. if(e.compareTo((E) current.element) < 0){ // 小于->
  17. current = current.left; //指到left->
  18. }else if(e.compareTo((E) current.element) > 0){ // 大于->
  19. current = current.right; //指到right->
  20. }else return true; // 相同即找到
  21. }
  22. return false; // 没找到
  23. }
  24. /* 递归search
  25. public boolean search(E e) {
  26. return search(root, e);
  27. }
  28. public boolean search(TreeNode<E> root, E e) {
  29. if (root == null)
  30. return false;
  31. else if (e.compareTo(root.element) < 0)
  32. return search(root.left, e);
  33. else if (e.compareTo(root.element) > 0)
  34. return search(root.right, e);
  35. else
  36. return true;
  37. }
  38. * */
  39. // 插入
  40. @Override
  41. public boolean insert(E e){
  42. if(root == null){
  43. root = createNewNode(e); //如果树为空,创建一个新的根结点
  44. }else {
  45. // 否则寻找新元素父节点的位置
  46. TreeNode<E> parent = null;
  47. TreeNode<E> current = root;
  48. while(current != null){
  49. if(e.compareTo(current.element) < 0){
  50. parent = current;
  51. current = current.left;
  52. }else if(e.compareTo(current.element) > 0){
  53. parent = current;
  54. current = current.left;
  55. }else return false;
  56. }
  57. // 链接父结点
  58. if(e.compareTo(parent.element) < 0)
  59. parent.left = createNewNode(e);
  60. else
  61. parent.right = createNewNode(e);
  62. }
  63. size++;
  64. return true;
  65. }
  66. protected TreeNode<E> createNewNode(E e){
  67. return new TreeNode<>(e);
  68. }
  69. // 中序遍历
  70. @Override
  71. public void inorder(){
  72. inorder(root);
  73. }
  74. protected void inorder(TreeNode<E> root){
  75. if(root == null){ // 树为空时结束递归
  76. return;
  77. }
  78. inorder(root.left); //递归左结点
  79. System.out.print(root.element + " "); // 中间结点
  80. inorder(root.right); // 递归右结点
  81. }
  82. // 后序遍历
  83. @Override
  84. public void postorder(){
  85. postorder(root);
  86. }
  87. protected void postorder(TreeNode<E> root){
  88. if(root == null){
  89. return;
  90. }
  91. postorder(root.left);
  92. postorder(root.right);
  93. System.out.print(root.element + " ");
  94. }
  95. // 前序遍历
  96. public void preorder(){
  97. preorder(root);
  98. }
  99. protected void preorder(TreeNode<E> root){
  100. if(root == null){
  101. return ;
  102. }
  103. System.out.print(root.element + " ");
  104. preorder(root.left);
  105. preorder(root.right);
  106. }
  107. // 树结点class
  108. public static class TreeNode<E>{
  109. protected E element;
  110. protected TreeNode<E> left;
  111. protected TreeNode<E> right;
  112. public TreeNode(E e){
  113. element = e;
  114. }
  115. }
  116. @Override
  117. public int getSize(){
  118. return size;
  119. }
  120. public TreeNode<E> getRoot(){
  121. return root;
  122. }
  123. // 以数组线性表返回结点路径
  124. public java.util.ArrayList<TreeNode<E>> path(E e){
  125. java.util.ArrayList<TreeNode<E>> list = new java.util.ArrayList<>();
  126. TreeNode<E> current = root;
  127. while(current != null){
  128. list.add(current);
  129. if(e.compareTo(current.element) < 0){
  130. current = current.left;
  131. }else if(e.compareTo(current.element) > 0){
  132. current = current.right;
  133. }else break;
  134. }
  135. return list;
  136. }
  137. /**删除*/
  138. @Override
  139. public boolean delete(E e){
  140. TreeNode<E> parent = null;
  141. TreeNode<E> current = root;
  142. // 定位current和parent
  143. while(current != null){
  144. if(e.compareTo(current.element) < 0){
  145. parent = current;
  146. current = current.left;
  147. }else if(e.compareTo(current.element) > 0){
  148. parent = current;
  149. current = current.right;
  150. }else break;
  151. }
  152. if(current == null){
  153. return false; // 结点不在树中
  154. }
  155. // 1、无左子结点
  156. if(current.left == null){
  157. if(parent == null){
  158. root = current.right; // 没有父结点 就设为根结点
  159. }else {
  160. if(e.compareTo(parent.element) < 0){ // 删除current结点
  161. parent.left = current.right;
  162. }else {
  163. parent.right = current.right;
  164. }
  165. }
  166. }else{ // 2、有左子结点
  167. TreeNode<E> parentOfRightMost = current;
  168. TreeNode<E> rightMost = current.left;
  169. // 定位rightMost和parentOfRightMost
  170. while (rightMost.right != null){
  171. parentOfRightMost = rightMost;
  172. rightMost = rightMost.right;
  173. }
  174. current.element = rightMost.element; // 用rightMost替换current
  175. // 删除rightMost结点
  176. if(parentOfRightMost.right == rightMost){
  177. parentOfRightMost.right = rightMost.left;
  178. }else{
  179. parentOfRightMost.left = rightMost.left;
  180. }
  181. }
  182. size--;
  183. return true;
  184. }
  185. // 遍历迭代器
  186. @Override
  187. public java.util.Iterator<E> iterator() {
  188. return new InorderIterator();
  189. }
  190. private class InorderIterator implements java.util.Iterator<E>{
  191. private java.util.ArrayList<E> list = new java.util.ArrayList<>();
  192. private int current = 0;
  193. public InorderIterator(){
  194. inorder();
  195. }
  196. private void inorder(){
  197. inorder(root);
  198. }
  199. private void inorder(TreeNode<E> root){
  200. if(root == null){
  201. return;
  202. }
  203. inorder(root.left);
  204. list.add(root.element);
  205. inorder(root.right);
  206. }
  207. @Override
  208. public boolean hasNext(){
  209. if(current < list.size()){
  210. return true;
  211. }
  212. return false;
  213. }
  214. @Override
  215. public E next(){
  216. return list.get(current++);
  217. }
  218. @Override
  219. public void remove(){
  220. if(current == 0){
  221. throw new IllegalStateException();
  222. }
  223. delete(list.get(--current));
  224. list.clear();
  225. inorder();
  226. }
  227. }
  228. @Override
  229. public void clear(){
  230. root = null;
  231. size = 0;
  232. }
  233. }

五、数据压缩:哈夫曼编码

哈夫曼编码中的字符编码基于字符出现的次数使用二叉树构建。使用贪心算法,算法总是选择具有最小权重的两棵树,并且创造一个新的父结点

 接下来编写一个程序,用户输入字符串,程序将会输出每个字符出现的次数以及其哈夫曼编码:

  1. import java.util.Scanner;
  2. public class HuffmanCode {
  3. public static void main(String[] args){
  4. Scanner input = new Scanner(System.in);
  5. System.out.print("Enter text: ");
  6. String text = input.nextLine();
  7. // 计算字符出现次数
  8. int[] counts = getCharacterFrequency(text);
  9. System.out.printf("%-15s%-15s%-15s%-15s\n","ASCII Code","Character","Frequency","Code");
  10. // 基于counts得到哈夫曼树
  11. Tree tree = getHuffmanTree(counts);
  12. String[] codes = getCode(tree.root);
  13. for(int i = 0; i < codes.length; i++){
  14. if(counts[i] != 0){
  15. System.out.printf("%-15s%-15s%-15s%-15s\n",i, (char)i + "",counts[i],codes[i]);
  16. }
  17. }
  18. }
  19. // 获取每个叶子结点中字符的编码
  20. public static String[] getCode(Tree.Node root) {
  21. if(root == null){
  22. return null;
  23. }
  24. String[] codes = new String[2 *128];
  25. assignCode(root,codes);
  26. return codes;
  27. }
  28. // 给树中每个结点赋予编码
  29. private static void assignCode(Tree.Node root, String[] codes){
  30. if(root.left != null){
  31. root.left.code = root.code + "0";
  32. assignCode(root.left, codes);
  33. root.right.code = root.code + "1";
  34. assignCode(root.right,codes);
  35. }else {
  36. codes[(int) root.element] = root.code;
  37. }
  38. }
  39. // 返回一颗哈夫曼树
  40. public static Tree getHuffmanTree(int[] counts){
  41. // 创建单结点树并添加到堆中
  42. Heap<Tree> heap = new Heap<>();
  43. for(int i = 0; i < counts.length; i++){
  44. if(counts[i] > 0){
  45. heap.add(new Tree(counts[i],(char)i));
  46. }
  47. }
  48. // while迭代
  49. while(heap.getSize() > 1){
  50. Tree t1 = heap.remove(); //每次将权重最小的两个子树从堆中删除
  51. Tree t2 = heap.remove();
  52. heap.add(new Tree(t1, t2)); //t1,t2组合成新树。接着添加新树到堆中
  53. }
  54. return heap.remove();
  55. }
  56. // 创建一个数组计算256个ASCII字符出现的次数
  57. public static int[] getCharacterFrequency(String text){
  58. int[] counts = new int[256];
  59. for(int i = 0; i < text.length(); i++){
  60. counts[(int)text.charAt(i)]++;
  61. }
  62. return counts;
  63. }
  64. public static class Tree implements Comparable<Tree>{
  65. Node root;
  66. public Tree(Tree t1, Tree t2){
  67. root = new Node();
  68. root.left = t1.root;
  69. root.right = t2.root;
  70. root.weight = t1.root.weight + t2.root.weight;
  71. }
  72. public Tree(int weight, char element) {
  73. root = new Node(weight, element);
  74. }
  75. @Override
  76. public int compareTo(Tree t) {
  77. if(root.weight < t.root.weight){
  78. return 1;
  79. }else if(root.weight == t.root.weight){
  80. return 0;
  81. }else return -1;
  82. }
  83. public class Node{
  84. char element;
  85. int weight;
  86. Node left;
  87. Node right;
  88. String code = "";
  89. public Node() {
  90. }
  91. public Node(int weight, char element){
  92. this.weight = weight;
  93. this.element = element;
  94. }
  95. }
  96. }
  97. }

运行结果如下: 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/572345
推荐阅读
相关标签
  

闽ICP备14008679号