二叉树的应用
1,哈夫曼树和哈夫曼编码
//转载至:https://blog.csdn.net/jdhanhua/article/details/6621026
1.1首先是Node类,因为每次取出两个最小值都行从新排序,将Node实现
Comparable接口用于排序
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class Node implements Comparable<Node>{ 2 public int data=Integer.MAX_VALUE; 3 public Node lchild=null; 4 public Node rchild=null; 5 6 public Node(){} 7 public Node(int data){ 8 this.data=data; 9 } 10 11 @Override 12 public int compareTo(Node o) { 13 if(o.data>this.data) 14 return 1; 15 if(o.data<this.data) 16 return -1; 17 return 0; 18 } 19 }
1.2,hafuffmanTree类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import java.util.*; 2 3 /** 4 * 5 * 建树, 6 * 输出哈夫曼编码 7 */ 8 9 10 public class HaffmanTree { 11 private Node root=new Node(); 12 13 /** 14 * 建树-①根据已排序的升序频率数组建树,每次取出前两个创建树,根节点为前两个和 15 * ②将根节点插入数组,重新排序,重复①,直至结束 16 * https://blog.csdn.net/jdhanhua/article/details/6621026 17 */ 18 public Node createHaffmanTree(List<Node> array){ 19 while(array.size()>1){ 20 Collections.sort(array); 21 Node left=array.get(array.size()-1); 22 Node right=array.get(array.size()-2); 23 Node newNode=new Node(left.data+right.data); 24 newNode.lchild=left; 25 newNode.rchild=right; 26 array.remove(left); 27 array.remove(right); 28 array.add(newNode); 29 //System.out.println("data: "+newNode.data); 30 } 31 return array.get(0); 32 } 33 34 /** 35 * 打印编码 36 https://www.it610.com/article/1296876477320601600.htm 37 遍历的时候加一个编码栈 38 * 遍历的时候,进入左子树,0入栈,右子树,1入栈, 39 * 遍历到叶子节点-输出,打印栈, 40 *返回时栈顶退栈 41 */ 42 public void HaffmanCode(Node root,Stack<Integer>stack){ 43 if(root==null) 44 return; 45 if(root.rchild==null&&root.rchild==null)//叶子节点 46 System.out.println(root.data+" "+stack); 47 stack.push(0); 48 HaffmanCode(root.lchild,stack); 49 stack.pop(); 50 51 stack.push(1); 52 HaffmanCode(root.rchild,stack); 53 stack.pop(); 54 } 55 //打印树-复制上一篇 56 //H为频率数组个数 57 public void printTree(Node root,int H){ 58 int h=H; 59 //System.out.println("树高:"+H); 60 if(H==0) 61 System.out.println("树空,无打印"); 62 else{ 63 System.out.println("打印树:"); 64 Queue<Node> queue=new LinkedList<>(); 65 queue.add(root); 66 int height=1; 67 //记录每层孩子个数 68 int len=1; 69 while(h>0){ 70 int length=0; 71 String space=""; 72 for(int i=0;i<(((Math.pow(2,H)+1)*3)/(Math.pow(2,height)+1));i++) 73 space+=" "; 74 for(int i=0;i<len;i++){ 75 Node curroot=queue.poll(); 76 if(curroot.data==Integer.MAX_VALUE){ 77 System.out.print(space); 78 }else 79 System.out.print(space+curroot.data); 80 81 if(curroot.lchild!=null){ 82 queue.add(curroot.lchild); 83 } 84 else 85 queue.add(new Node()); 86 length++; 87 if(curroot.rchild!=null){ 88 queue.add(curroot.rchild); 89 } 90 else 91 queue.add(new Node()); 92 length++; 93 } 94 System.out.println(); 95 System.out.println(); 96 len=length; 97 height++; 98 h--; 99 } 100 System.out.println(); 101 } 102 } 103 104 //1,2,5,8,7,9 105 public static void main(String args[]) { 106 List<Node> l=new ArrayList<Node>(); 107 l.add(new Node(1)); 108 l.add(new Node(2)); 109 l.add(new Node(5)); 110 l.add(new Node(8)); 111 l.add(new Node(7)); 112 l.add(new Node(9)); 113 int H=l.size(); 114 System.out.println("l "+l.size()); 115 116 HaffmanTree h=new HaffmanTree(); 117 h.root=h.createHaffmanTree(l); 118 119 h.printTree(h.root,H); 120 Stack<Integer> stack=new Stack<>(); 121 h.HaffmanCode(h.root,stack); 122 123 } 124 125 126 }
2,二叉查找树
2.1,先实现二叉查找树的排序功能
如果在建树的时候安照,若插入节点值小于根节点值,往根节点左子树继续,大于根节点值
往右子树继续,如无左/右子树则插入。建树完成后,形成的树的中序遍历结构就是升序的。
如按 {4,2,3,8,7,9,1} 顺序插入建树如图,中序遍历为:1234789
Node类同hafuffman 树,就不写了
sortBiTree
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * 二叉搜索树的排序功能 3 * 给你个待排序数组 4 * 建树,中序遍历树 5 * 6 * 缺点: 7 * 当待排序的序列为顺序或逆序时,很不稳定,需要平衡二叉树或红黑树那种 8 * 后面再学 9 */ 10 import java.util.LinkedList; 11 import java.util.Queue; 12 public class SortBitree { 13 private Node root=null; 14 15 16 /** 17 * 建树 18 * 空-插入根节点,比根节点小,进入左子树, 19 * 比根节点大,进入右子树 20 */ 21 public void inseart(Node root,int data){ 22 //System.out.println(root.data); 23 if(root==null) 24 this.root=new Node(data); 25 else{ 26 //元素不能重复, 27 if(data<root.data){ 28 if(root.lchild==null){ 29 root.lchild=new Node(data); 30 } 31 else{ 32 inseart(root.lchild,data); 33 } 34 } 35 else{ 36 if(root.rchild==null){ 37 root.rchild=new Node(data); 38 }else 39 inseart(root.rchild,data); 40 } 41 } 42 } 43 //递归求树高-用于打印 44 //递归 45 public int treeHeightRec(Node root){ 46 if(root==null||root.data==Integer.MAX_VALUE) 47 return 0; 48 else{ 49 int a =treeHeightRec(root.lchild); 50 int b = treeHeightRec(root.rchild); 51 return (a>b)?(a+1):(b+1); 52 } 53 } 54 //打印树--233,复制前一篇的方法,如果树层数很深时,打印的比较别扭 55 public void printTree(Node root){ 56 int H=treeHeightRec(root); 57 int h=H; 58 //System.out.println("树高:"+H); 59 if(H==0) 60 System.out.println("树空,无打印"); 61 else{ 62 System.out.println("打印树:"); 63 Queue<Node> queue=new LinkedList<>(); 64 queue.add(root); 65 int height=1; 66 //记录每层孩子个数 67 int len=1; 68 while(h>0){ 69 int length=0; 70 String space=""; 71 for(int i=0;i<(((Math.pow(2,H)+1)*3)/(Math.pow(2,height)+1));i++) 72 space+=" "; 73 for(int i=0;i<len;i++){ 74 Node curroot=queue.poll(); 75 if(curroot.data==Integer.MAX_VALUE){ 76 System.out.print(space); 77 }else 78 System.out.print(space+curroot.data); 79 80 if(curroot.lchild!=null){ 81 queue.add(curroot.lchild); 82 } 83 else 84 queue.add(new Node()); 85 length++; 86 if(curroot.rchild!=null){ 87 queue.add(curroot.rchild); 88 } 89 else 90 queue.add(new Node()); 91 length++; 92 } 93 System.out.println(); 94 System.out.println(); 95 len=length; 96 height++; 97 h--; 98 } 99 System.out.println(); 100 } 101 } 102 //中序遍历 103 public void inOrder(Node root){ 104 if(root==null) 105 return; 106 inOrder(root.lchild); 107 System.out.print(root.data+" "); 108 inOrder(root.rchild); 109 } 110 111 public static void main(String args[]) { 112 SortBitree t=new SortBitree(); 113 SortBitree t1=new SortBitree(); 114 SortBitree t2=new SortBitree(); 115 int[] array={4,2,3,8,7,9,1}; 116 int[] array1={1,2,3,4,5,6,7}; 117 int[] array2={7,6,5,4,3,2,1}; 118 119 for(int i=0;i<array.length;i++){ 120 t.inseart(t.root,array[i]); 121 } 122 System.out.print("排序后的序列: ");t.inOrder(t.root); 123 System.out.println(); 124 t.printTree(t.root); 125 126 for(int i=0;i<array.length;i++){ 127 t1.inseart(t1.root,array1[i]); 128 } 129 System.out.print("排序后的序列: ");t1.inOrder(t1.root); 130 System.out.println(); 131 t1.printTree(t1.root); 132 133 for(int i=0;i<array.length;i++){ 134 t2.inseart(t.root,array2[i]); 135 } 136 System.out.print("排序后的序列: ");t2.inOrder(t2.root); 137 System.out.println(); 138 t2.printTree(t2.root); 139 140 } 141 142 143 144 }
2.2,完整二叉查找树
排序功能涉及了二叉查找树的插入功能,还有查找,删除功能
查找功能比较简单,二叉遍历一遍,主要是删除功能,比较复杂
/**删除
* ①删除最小/大值,最小/大值-最左/右节点
* -空树
* -只有一个根节点
* -根节点无左/右子树(删除根节点)
* -有左/右子树且非空
*
* ②删除一个节点,-树空
* -是否在树中
* -无左右节点,直接删
* -有左节点(只有左子树),删除左子树的最大节点-返回最大节点,
* 将返回的节点代替被删节点
* -只要有右节点,删除右子树的最小值,将返回的节点代替被删节点
*/
完整代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //https://www.cnblogs.com/songdechiu/p/6821168.html 2 //转载一个老哥,太猛了-(key,value) 3 //这篇也不错---(value) 4 //https://zhuanlan.zhihu.com/p/84517029 5 6 import java.util.LinkedList; 7 import java.util.Queue; 8 9 /**二叉查找树-完成的 10 * 建树-就是不停插入(二叉排序树简单铺垫了,直接复制过来) 11 * 插入 12 * 13 * 查找 14 * 15 * 删除 16 */ 17 18 public class SearchBiTree { 19 private Node root=null; 20 21 22 /** 23 * 打印等辅助函数 24 */ 25 //递归求树高-用于打印树 26 //递归 27 public int treeHeightRec(Node root){ 28 if(root==null||root.data==Integer.MAX_VALUE) 29 return 0; 30 else{ 31 int a =treeHeightRec(root.lchild); 32 int b = treeHeightRec(root.rchild); 33 return (a>b)?(a+1):(b+1); 34 } 35 } 36 //打印树--233,复制前一篇的方法,如果树层数很深时,打印的比较别扭 37 public void printTree(Node root){ 38 int H=treeHeightRec(root); 39 int h=H; 40 //System.out.println("树高:"+H); 41 if(H==0) 42 System.out.println("树空,无打印"); 43 else{ 44 System.out.println("打印树:"); 45 Queue<Node> queue=new LinkedList<>(); 46 queue.add(root); 47 int height=1; 48 //记录每层孩子个数 49 int len=1; 50 while(h>0){ 51 int length=0; 52 String space=""; 53 for(int i=0;i<(((Math.pow(2,H)+1)*3)/(Math.pow(2,height)+1));i++) 54 space+=" "; 55 for(int i=0;i<len;i++){ 56 Node curroot=queue.poll(); 57 if(curroot.data==Integer.MAX_VALUE){ 58 System.out.print(space); 59 }else 60 System.out.print(space+curroot.data); 61 62 if(curroot.lchild!=null){ 63 queue.add(curroot.lchild); 64 } 65 else 66 queue.add(new Node()); 67 length++; 68 if(curroot.rchild!=null){ 69 queue.add(curroot.rchild); 70 } 71 else 72 queue.add(new Node()); 73 length++; 74 } 75 System.out.println(); 76 System.out.println(); 77 len=length; 78 height++; 79 h--; 80 } 81 System.out.println(); 82 } 83 } 84 //中序遍历 85 public void inOrder(Node root){ 86 if(root==null) 87 return; 88 inOrder(root.lchild); 89 System.out.print(root.data+" "); 90 inOrder(root.rchild); 91 } 92 93 94 /** 95 * 以下为新加内容 96 */ 97 //查找--是否存在 98 public boolean isExit(Node root,int data){ 99 if(root==null)//树空 100 return false; 101 if(root.data==data) 102 return true; 103 else if(data<root.data){ 104 if(root.lchild==null) 105 return false; 106 else 107 return isExit(root.lchild,data); 108 }else{ 109 if(root.rchild==null) 110 return false; 111 else 112 return isExit(root.rchild,data); 113 } 114 } 115 //插入-先搜索,不存在则插入, 116 public void inseart(Node root,int data){ 117 if(!isExit(root,data)) 118 //System.out.println(root.data); 119 if(root==null) 120 this.root=new Node(data); 121 else{ 122 //元素不能重复, 123 if(data<root.data){ 124 if(root.lchild==null){ 125 root.lchild=new Node(data); 126 } 127 else{ 128 inseart(root.lchild,data); 129 } 130 } 131 else{ 132 if(root.rchild==null){ 133 root.rchild=new Node(data); 134 }else 135 inseart(root.rchild,data); 136 } 137 } 138 else 139 System.out.println(data+"已在排序树中"); 140 } 141 142 /**删除 143 * ①删除最小/大值,最小/大值-最左/右节点 144 * -空树 145 * -只有一个根节点 146 * -根节点无左/右子树(删除根节点) 147 * -有左/右子树且非空 148 * 149 * ②删除一个节点,-树空 150 * -是否在树中 151 * -无左右节点,直接删 152 * -有左节点(只有左子树),删除左子树的最大节点-返回最大节点, 153 * 将返回的节点代替被删节点 154 * -只要有右节点,删除右子树的最小值,将返回的节点代替被删节点 155 */ 156 //删除最小值 157 public Node deleteMin(Node root){ 158 //空树 159 if(root==null){ 160 System.out.println("树空,无最小值"); 161 return null; 162 } 163 //只有一个根节点 164 else if(root.lchild==null&&root.rchild==null){ 165 this.root=null; 166 return root; 167 } 168 //根节点无左子树(删除根节点) 169 else if(root.lchild==null){ 170 Node n=new Node(root.data); 171 root.data=root.rchild.data; 172 root.lchild=root.rchild.lchild; 173 root.rchild=root.rchild.rchild; 174 return n; 175 } 176 //有左子树且非空 177 Node preNode=new Node(); 178 while(root.lchild!=null){ 179 preNode=root; 180 root=root.lchild; 181 } 182 preNode.lchild=root.rchild; 183 return root; 184 } 185 //删除最大值 186 public Node deleteMax(Node root){ 187 //空树 188 if(root==null){ 189 System.out.println("树空,无最大值"); 190 return null; 191 } 192 //只有一个根节点 193 else if(root.lchild==null&&root.rchild==null){ 194 this.root=null; 195 return root; 196 } 197 //根节点无右子树(删除根节点) 198 else if(root.rchild==null){ 199 Node n=new Node(root.data); 200 root.data=root.lchild.data; 201 root.lchild=root.lchild.lchild; 202 root.rchild=root.lchild.rchild; 203 return n; 204 } 205 //有右子树且非空 206 Node preNode=new Node(); 207 while(root.rchild!=null){ 208 preNode=root; 209 root=root.rchild; 210 } 211 preNode.rchild=root.lchild; 212 return root; 213 } 214 //删除一个值 215 public void delete(Node root,int data){ 216 //在树中(树非空) 217 if(!isExit(root,data)){ 218 System.out.println("值不在树中"); 219 } 220 //只有一个节点-即删除根节点 221 if(root.lchild==null&&root.rchild==null){ 222 this.root=null; 223 } 224 //先遍历到节点,在删除-将替换节点的值赋给该节点, 225 //记录被删节点何其前驱节点-非递归遍历法 226 else{ 227 Node preNode=root; 228 String lORr="";//记录前驱节点的哪个孩子时待删节点 229 while(root.data!=data){ 230 if(data<root.data){ 231 preNode=root; 232 lORr="l"; 233 root=root.lchild; 234 } 235 else if(data>root.data){ 236 preNode=root; 237 lORr="r"; 238 root=root.rchild; 239 } 240 } 241 //此时root即待删除节点; 242 //该节点无子节点 243 if(root.lchild==null&&root.rchild==null){ 244 if(lORr=="l") 245 preNode.lchild=null; 246 else 247 preNode.rchild=null; 248 } 249 //只有左子节点 250 else if(root.lchild!=null&&root.rchild==null){ 251 //如果左子节点是叶子节点--因为根节点表示问题,左子树只有根节点,数据是写入特殊值Integer.MAX_VALUE 252 //而不是删掉=null 253 if(root.lchild.lchild==null&&root.lchild.rchild==null){ 254 if(lORr=="l") 255 preNode.lchild=root.lchild; 256 else 257 preNode.rchild=root.lchild; 258 }else{ 259 Node replaceNode=deleteMax(root.lchild); 260 root.data=replaceNode.data; 261 } 262 } 263 //有右子节点 264 else if(root.rchild!=null){ 265 if(root.rchild.lchild==null&&root.rchild.rchild==null){ 266 if(lORr=="l"){ 267 preNode.lchild=root.rchild; 268 root.rchild.lchild=root.lchild;//接替root的左子树; 269 } 270 else{ 271 preNode.rchild=root.rchild; 272 root.rchild.lchild=root.lchild; 273 } 274 }else{ 275 Node replaceNode=deleteMin(root.rchild); 276 root.data=replaceNode.data; 277 } 278 } 279 280 281 } 282 } 283 public static void main(String args[]) { 284 SearchBiTree t=new SearchBiTree(); 285 int[] array={8,4,6,16,14,18,2}; 286 287 for(int i=0;i<array.length;i++){ 288 t.inseart(t.root,array[i]); 289 } 290 System.out.print("排序后的序列: ");t.inOrder(t.root); 291 System.out.println(); 292 t.printTree(t.root); 293 294 t.inseart(t.root,12); 295 t.inseart(t.root,5); 296 t.printTree(t.root); 297 t.inseart(t.root,16); 298 t.inseart(t.root,13); 299 t.printTree(t.root); 300 t.delete(t.root,14); 301 t.printTree(t.root); 302 303 304 System.out.println(t.deleteMax(t.root).data); 305 t.printTree(t.root); 306 t.deleteMin(t.root); 307 t.printTree(t.root); 308 309 /** 310 * 删除 311 */ 312 313 SearchBiTree t2=new SearchBiTree(); 314 t2.printTree(t2.root); 315 t2.inseart(t2.root,2); 316 t2.printTree(t2.root); 317 t2.deleteMin(t2.root); 318 t2.printTree(t2.root); 319 t2.inseart(t2.root,11); 320 t2.inseart(t2.root,10); 321 t2.inseart(t2.root,9); 322 t2.inseart(t2.root,8); 323 t2.printTree(t2.root); 324 325 System.out.println(t2.deleteMax(t2.root).data); 326 t2.printTree(t2.root); 327 328 329 330 331 } 332 }