当前位置:   article > 正文

平衡二叉树(AVL)【java实现+图解】_java 二叉平衡树

java 二叉平衡树

目录

一、平衡二叉树(AVL)

二、平衡二叉树的四种旋转

1.右旋转

2.左旋转

3. 左右旋转

4. 右左旋转

 三、基于二叉搜索树之平衡二叉树的代码实现

1.具体方法思路

2.java代码实现 


一、平衡二叉树(AVL)

一种自平衡二叉搜索树,它是在每个节点上增加一个平衡因子,然后通过调整树中节点的高度来保持树的平衡。平衡因子是左子树的高度减去右子树的高度,用它可以表示出当前节点的平衡程度。对于任意一个结点左子树和右子树的高度差不能超过1,当一个节点的平衡因子绝对值大于1时,这个节点就被称为不平衡节点。

二、平衡二叉树的四种旋转

1.右旋转

 

  1. //左旋转
  2. public Node leftSpin(Node x){
  3. Node y = x.right;
  4. Node t2 = y.left;
  5. x.right = t2;
  6. y.left = x;
  7. //更新节点的高度
  8. x.height = Math.max(getHight(x.left),getHight(x.right))+1;
  9. y.height = Math.max(getHight(y.left),getHight(y.right))+1;
  10. return y;
  11. }

 

2.左旋转

 

  1. //右旋转
  2. public Node rightSpin(Node x){
  3. Node y = x.left;
  4. Node t2 = y.right;
  5. x.left = t2;
  6. y.right = x;
  7. //更新节点的高度
  8. x.height = Math.max(getHight(x.left),getHight(x.right))+1;
  9. y.height = Math.max(getHight(y.left),getHight(y.right))+1;
  10. return y;
  11. }

3. 左右旋转

先旋转成上面只需要右旋转的情况,再经过右旋转成平衡二叉树

4. 右左旋转

先旋转成上面只需要左旋转的情况,再经过左旋转成平衡二叉树

 三、基于二叉搜索树之平衡二叉树的代码实现

1.具体方法思路

主要方法:

添加:每次添加一个节点后更新输的高度,平衡因子可能改变,依据平衡因子对二叉树进行调整;

删除:每删除一个节点后,也需要更新输的高度,平衡因子可能改变,依据平衡因子对二叉树进行调整。

辅助方法:

判断是否是二叉搜索树:通过中序遍历,将节点的前一个值与后一个值比较;

判断是否是平衡二叉树:通过判断每个子树的平衡因子的是否在[-1,1]区间内。

2.java代码实现 

  1. import java.util.*;
  2. import java.util.stream.Collectors;
  3. public class AVL<T extends Comparable<T>> {
  4. public class Node {
  5. T val;
  6. Node left;
  7. Node right;
  8. //以该节点为根的树的高度
  9. int height;
  10. //统计单词出现的次数
  11. int count;
  12. public Node(T val) {
  13. this.val = val;
  14. this.height = 1;//默认高度为1
  15. this.count = 1;
  16. }
  17. @Override
  18. public String toString() {
  19. return String.format("val:%s,heiget:%d,count:%d",this.val,this.height,this.count);
  20. }
  21. }
  22. private Node root;
  23. private Integer size;
  24. public AVL() {
  25. this.root = null;
  26. this.size = 0;
  27. }
  28. public boolean isEmpt() {
  29. return this.size == 0;
  30. }
  31. public Integer getSize() {
  32. return this.size;
  33. }
  34. //验证是否是二叉搜索树
  35. public boolean isBinaryTree(){
  36. List<T> list = new ArrayList<>();
  37. midTraversal(list,this.root);
  38. for (int i = 1; i < list.size(); i++) {
  39. if (list.get(i-1).compareTo(list.get(i))>0){
  40. return false;
  41. }
  42. }
  43. return true;
  44. }
  45. //获取当前节点的高度
  46. public int getHight(Node node){
  47. if (node==null){
  48. return 0;
  49. }
  50. return node.height;
  51. }
  52. //获取当前节点的平衡因子
  53. public int getBalanceFactor(Node node){
  54. if (node==null){
  55. return 0;
  56. }
  57. return getHight(node.left)-getHight(node.right);
  58. }
  59. public boolean isBalanceTree(){
  60. return isBalanceTree(this.root);
  61. }
  62. //判断以node为节点的树是否是平衡二叉树
  63. private boolean isBalanceTree(Node node){
  64. if (node==null){
  65. return true;
  66. }
  67. int balanceFactor = Math.abs(getBalanceFactor(node));
  68. if (balanceFactor>1){
  69. return false;
  70. }else {
  71. return isBalanceTree(node.left)&&isBalanceTree(node.right);
  72. }
  73. }
  74. //左旋转
  75. public Node leftSpin(Node x){
  76. Node y = x.right;
  77. Node t2 = y.left;
  78. x.right = t2;
  79. y.left = x;
  80. //更新节点的高度
  81. x.height = Math.max(getHight(x.left),getHight(x.right))+1;
  82. y.height = Math.max(getHight(y.left),getHight(y.right))+1;
  83. return y;
  84. }
  85. //右旋转
  86. public Node rightSpin(Node x){
  87. Node y = x.left;
  88. Node t2 = y.right;
  89. x.left = t2;
  90. y.right = x;
  91. //更新节点的高度
  92. x.height = Math.max(getHight(x.left),getHight(x.right))+1;
  93. y.height = Math.max(getHight(y.left),getHight(y.right))+1;
  94. return y;
  95. }
  96. //添加
  97. public void add(T val) {
  98. this.root = add(this.root, val);
  99. }
  100. private Node add(Node node, T val) {
  101. if (node == null) {
  102. this.size++;
  103. Node leafNode = new Node(val);
  104. return leafNode;
  105. }
  106. //当前节点的值小于添加的val,因此val做右孩子
  107. if (node.val.compareTo(val) < 0) {
  108. node.right = add(node.right, val);
  109. //更新高度
  110. node.height = Math.max(getHight(node.left),getHight(node.right))+1;
  111. } else if (node.val.compareTo(val) > 0){
  112. node.left = add(node.left, val);
  113. //更新高度
  114. node.height = Math.max(getHight(node.left),getHight(node.right))+1;
  115. }else {
  116. node.count++;
  117. }
  118. //添加后还要判断是否是平衡二叉树
  119. Node resNode = node;
  120. int balanceFactor = getBalanceFactor(node);
  121. if (balanceFactor>1&&getBalanceFactor(node.left)>=0){
  122. //右
  123. resNode = rightSpin(node);
  124. }else if (balanceFactor>1&&getBalanceFactor(node.left)<0){
  125. //左右
  126. node.left = leftSpin(node.left);
  127. resNode = rightSpin(node);
  128. }else if (balanceFactor<-1&&getBalanceFactor(node.right)<=0){
  129. //左
  130. resNode = leftSpin(node);
  131. }else if (balanceFactor<-1&&getBalanceFactor(node.right)>0){
  132. //右左
  133. node.right = rightSpin(node.right);
  134. resNode = leftSpin(node);
  135. }
  136. return resNode;
  137. }
  138. //删除操作
  139. //删除树中的val
  140. public void remove(T val){
  141. if (!contain(val)){
  142. return;
  143. }
  144. this.root = remove(this.root,val);
  145. }
  146. /**
  147. * 删除val
  148. * @param node
  149. * @param val
  150. * @return
  151. */
  152. public Node remove(Node node, T val){
  153. // 递归终止条件
  154. if (node == null) {
  155. return null;
  156. }
  157. Node resNode = null;
  158. if (node.val.compareTo(val) == 0) {
  159. this.size--;
  160. if (node.right==null){
  161. //右子树为空
  162. resNode = node.left;
  163. }else if (node.left==null){
  164. //左子树为空
  165. resNode = node.right;
  166. }else {
  167. // 左右子树都不为空
  168. // 1.找到删除节点的后继
  169. Node suffixNode = getMinDG(node.right);
  170. // 2.删除后继
  171. suffixNode.right = remove(node.right,getMinDG(node.right).val);
  172. // 3.连接
  173. suffixNode.left = node.left;
  174. this.size++;
  175. // 返回删除后的根
  176. resNode = suffixNode;
  177. }
  178. }else if (node.val.compareTo(val)<0){
  179. node.right = remove(node.right,val);
  180. resNode = node;
  181. }else {
  182. node.left = remove(node.left,val);
  183. resNode = node;
  184. }
  185. //删除节点可能为叶子结点
  186. if (resNode==null){
  187. return null;
  188. }
  189. //更新高度
  190. resNode.height = Math.max(getHight(resNode.left),getHight(resNode.right))+1;
  191. int balanceFactor = getBalanceFactor(resNode);
  192. if (balanceFactor>1&&getBalanceFactor(resNode.left)>=0){
  193. //右
  194. resNode = rightSpin(resNode);
  195. }else if (balanceFactor>1&&getBalanceFactor(resNode.left)<0){
  196. //左右
  197. resNode.left = leftSpin(resNode.left);
  198. resNode = rightSpin(resNode);
  199. }else if (balanceFactor<-1&&getBalanceFactor(resNode.right)<=0){
  200. //左
  201. resNode = leftSpin(resNode);
  202. }else if (balanceFactor<-1&&getBalanceFactor(resNode.right)>0){
  203. //右左
  204. resNode.right = rightSpin(resNode.right);
  205. resNode = leftSpin(resNode);
  206. }
  207. return resNode;
  208. }
  209. private Node getMinDG(Node node) {
  210. // 递归终止条件
  211. if (node.left == null) {
  212. return node;
  213. }
  214. // 递归操作
  215. return getMinDG(node.left);
  216. }
  217. public String midTraversal() {
  218. List<T> res = new ArrayList<>();
  219. midTraversal(res, this.root);
  220. return res.stream().map(item -> item.toString()).collect(Collectors.joining(","));
  221. }
  222. /**
  223. * 中序遍历
  224. *
  225. * @param result
  226. * @param node 当前节点
  227. * @return
  228. */
  229. private void midTraversal(List<T> result, Node node) {
  230. if (node == null) {
  231. return;
  232. }
  233. midTraversal(result, node.left);
  234. result.add(node.val);
  235. midTraversal(result, node.right);
  236. }
  237. public void showTree(){
  238. showTree(this.root);
  239. }
  240. private void showTree(Node node){
  241. if (node == null) {
  242. return;
  243. }
  244. showTree(node.left);
  245. System.out.print(node);
  246. System.out.println("BalanceFactor:"+getBalanceFactor(node));
  247. showTree(node.right);
  248. }
  249. //查询是否存在val
  250. public boolean contain(T val){
  251. return contain(this.root,val);
  252. }
  253. private boolean contain(Node node,T val){
  254. // 递归的终止条件
  255. // 查询到低也没有找到
  256. if (node==null){
  257. return false;
  258. }
  259. // 递归操作
  260. if (node.val.compareTo(val)==0){
  261. return true;
  262. }else if (node.val.compareTo(val)<0){
  263. return contain(node.right,val);
  264. }else {
  265. return contain(node.left,val);
  266. }
  267. }
  268. //测试
  269. public static void main(String[] args) {
  270. AVL<String> bst = new AVL<>();
  271. List<String> list = ReadBookUtil.readBook("pride-and-prejudice.txt");
  272. list.stream().forEach(item->{
  273. bst.add(item);
  274. });
  275. System.out.println("是否是二分搜索树"+bst.isBinaryTree());
  276. System.out.println("是否是平衡二叉树"+bst.isBalanceTree());
  277. bst.showTree();
  278. }
  279. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/黑客灵魂/article/detail/858157
推荐阅读
相关标签
  

闽ICP备14008679号