当前位置:   article > 正文

Java实现平衡二叉树(AVLTree)的构建_java实现遍历平衡二叉树

java实现遍历平衡二叉树

        最近在学习数据结构上关于平衡二叉树的知识,看了严老师的思路,感觉用java写出递归的构建方式有点困难,因为其中的递归需要把引用传进去,所以感觉是要实现起来比较麻烦,所以就首先想到使用非递归的方式来实现构建平衡二叉树。

       使用非递归的方式,思路也很简单,就是为每一个结点都要定义一个平衡因子的属性,当成功向树中插入一个数据时,我就要进行回溯,看看有没有平衡因子的绝对值等于2的结点,如果有,那就需要进行旋转。当时的思路仅限于这些,接触java没有多久,目测如果实现起来,有点困难。

      所以,上网查询了一个博客写的代码,尽管不知道原作者是谁,不过还是贴上我参考的博客地址:http://blog.csdn.net/zxman660/article/details/7940190

      其中,我认为还有一个难题就是,我定义的结点使用了泛型,即结点的value也是使用的泛型<E>,所以在比较大小的时候,我就无从下手,可能是我接触java不太久的原因,当我参考上述博客的思路后,居然是这样实现的。

  1. void compare(E element, Node node){
  2. Comparable<? super E> e = (Comparable<? super E>)element;
  3. int cmp = e.compareTo(node.element);
  4. if(cmp > 0) //大于
  5. else if(cmp == 0) //等于
  6. else //小于
  7. }

 

     通过此次学习,虽然接触了平衡二叉树的构建,但还是感觉学到了不少的知识,并且对java的使用又有了更多的认识。

     有了上述的感悟,感觉还是写一个博客来收藏一下,等自己有时间,再补充一下结点删除的代码。

      可能本人代码在注释上提供的思路有限,如果有看不懂的地方,可以参考上面的博客地址的内容。

 

  1. package util;
  2. /**
  3. * 平衡二叉树
  4. * 定义:首先它是一种特殊的二叉排序树,其次它的左子树和右子树都是平衡二叉树,
  5. * 且左子树和右子树的深度之差不超过1
  6. * 平衡因子:可以定义为左子树的深度减去右子树的深度
  7. *
  8. * 平衡二叉树是对二叉排序树的优化,防止二叉排序树在最坏情况下平均查找时间为n,
  9. * 二叉排序树在此时形如一个单链表
  10. * 平衡二叉树查找元素的次数不超过树的深度,时间复杂度为logN
  11. */
  12. public class AVLTree<E> {
  13. /**根节点*/
  14. private Node<E> root = null;
  15. /**树中元素的个数*/
  16. private int size = 0;
  17. private static final int LEFT_HIGH = 1;
  18. private static final int RIGHT_HIGH = -1;
  19. private static final int EQUAL_HIGH = 0;
  20. public AVLTree(){}
  21. public boolean insertElement(E element){
  22. Node<E> t = root;
  23. if(t == null){
  24. /**将值复制给根节点,其父节点为空*/
  25. root = new Node(element, null);
  26. size = 1;
  27. return true;
  28. }
  29. int cmp = 0;
  30. Node<E> parent; /**用来保存t的父节点*/
  31. /**查找结点应存放的位置*/
  32. Comparable<? super E> e = (Comparable<? super E>)element;
  33. do{
  34. parent = t;
  35. cmp = e.compareTo(t.element);
  36. if(cmp < 0){
  37. t = t.left;
  38. }else if(cmp > 0){
  39. t = t.right;
  40. }else{
  41. return false;
  42. }
  43. }while(t != null);
  44. /**将结点存放在相应的位置*/
  45. Node<E> child = new Node(element, parent);
  46. if(cmp < 0){
  47. parent.left = child;
  48. }else{
  49. parent.right = child;
  50. }
  51. /**开始回溯,为根节点修改balabce,以便进行相应的调整*/
  52. while(parent != null){
  53. cmp = e.compareTo(parent.element);
  54. if(cmp < 0){
  55. parent.balance ++;
  56. }else{
  57. parent.balance --;
  58. }
  59. if(parent.balance == 0){/**从这以上的结点都不需要修改了,也不需要旋转了*/
  60. break;
  61. }
  62. if(Math.abs(parent.balance) == 2){
  63. fixAfterInsertion(parent);
  64. break;
  65. }
  66. parent = parent.parent;
  67. }
  68. size ++;
  69. return true;
  70. }
  71. private void fixAfterInsertion(Node<E> p) {
  72. if(p.balance == 2){
  73. leftBanance(p);
  74. }
  75. if(p.balance == -2){
  76. rightBalance(p);
  77. }
  78. }
  79. /**
  80. * 左平衡操作,即结点t的不平衡是因为左子树过深
  81. *
  82. * 1、如果新的结点插入到p的左孩子的左子树中,则直接进行右旋操作即可
  83. * t lc
  84. * / \ 右旋操作 / \
  85. * lc rc -------------> lcl t
  86. * / \ / / \
  87. * lcl lcr lcll lcr rc
  88. * /
  89. * lcll
  90. *
  91. * 2、如果新的结点插入到p的左孩子的右子树中,则需要进行分情况讨论
  92. *
  93. * 情况a:当p的左孩子的右子树根节点的balance = RIGHT_HIGH
  94. *
  95. * 1 1 4
  96. * / \ / \ / \
  97. * 2 6 左旋 4 6 右旋 2 1
  98. * / \ -------> / \ --------> / / \
  99. * 3 4 2 5 3 5 6
  100. * \ /
  101. * 5 3
  102. *
  103. *
  104. * 情况b:当p的左孩子的右子树根节点的balance = LEFT_HIGH
  105. *
  106. * 1 1 4
  107. * / \ / \ / \
  108. * 2 6 左旋 4 6 右旋 2 1
  109. * / \ -------> / --------> / \ \
  110. * 3 4 2 3 5 6
  111. * / / \
  112. * 5 3 5
  113. *
  114. * 情况c:当p的左孩子的右子树根节点的balance = EQUAL_HIGH
  115. *
  116. * 1 1 4
  117. * / \ / \ / \
  118. * 2 7 左旋 4 7 右旋 2 1
  119. * / \ -------> / \ --------> / \ / \
  120. * 3 4 2 6 3 5 6 7
  121. * / \ / \
  122. * 5 6 3 5
  123. * */
  124. private void leftBanance(Node<E> t) {
  125. Node<E> lc = t.left;
  126. switch(lc.balance){
  127. case LEFT_HIGH: /**新结点插入到t的左孩子的左子树上,需要单右旋处理*/
  128. lc.balance = EQUAL_HIGH;
  129. t.balance = EQUAL_HIGH;
  130. break;
  131. case RIGHT_HIGH: /**新结点插入到t的左孩子的右子树上,需要双旋处理*/
  132. Node<E> rd = lc.right;
  133. switch(rd.balance){
  134. case LEFT_HIGH:
  135. lc.balance = EQUAL_HIGH;
  136. t.balance = RIGHT_HIGH;
  137. break;
  138. case RIGHT_HIGH:
  139. lc.balance = LEFT_HIGH;
  140. t.balance = EQUAL_HIGH;
  141. break;
  142. case EQUAL_HIGH:
  143. t.balance = EQUAL_HIGH;
  144. lc.balance = EQUAL_HIGH;
  145. break;
  146. }
  147. rd.balance = EQUAL_HIGH;
  148. /**对t的左子树进行左旋处理*/
  149. left_Rotate(t.left);
  150. /**对t进行右旋处理*/
  151. right_Rotate(t);
  152. break;
  153. }
  154. }
  155. /**
  156. * 右平衡操作,即结点t的不平衡是因为右子树过深
  157. *
  158. * 1、如果新的结点插入到p的右孩子的右子树中,则直接进行左旋操作即可
  159. *
  160. * p r
  161. * / \ / \
  162. * l r 左旋操作 p rr
  163. * / \ -----------> / \ \
  164. * rl rr l rl rrr
  165. * \
  166. * rrr
  167. *
  168. *
  169. * 2、如果新的结点插入到p的右孩子的左子树中,则需要进行分情况讨论
  170. *
  171. * 情况a:当p的右孩子的左子树根节点的balance = LEFT_HIGH
  172. *
  173. * 1 1 4
  174. * / \ / \ / \
  175. * 2 3 右旋 2 4 左旋 1 3
  176. * / \ -------> / \ -------> / \ \
  177. * 4 5 6 3 2 6 5
  178. * / \
  179. * 6 5
  180. *
  181. * 情况b:当p的右孩子的左子树根节点的balance = RIGHT_HIGH
  182. *
  183. * 1 1 4
  184. * / \ / \ / \
  185. * 2 3 右旋 2 4 左旋 1 3
  186. * / \ -------> \ -------> / / \
  187. * 4 5 3 2 6 5
  188. * \ / \
  189. * 6 6 5
  190. *
  191. *
  192. * 情况C:当p的右孩子的左子树根节点的balance = EQUAL_HIGH
  193. * 1 1 4
  194. * / \ / \ / \
  195. * 2 3 右旋 2 4 左旋 1 3
  196. * / \ -------> / \ -------> / \ / \
  197. * 4 5 6 3 2 6 7 5
  198. * / \ / \
  199. * 6 7 7 5
  200. * */
  201. private void rightBalance(Node<E> p) {
  202. Node<E> rc = p.right;
  203. switch(rc.balance){
  204. case RIGHT_HIGH: /**新结点插入到t的右孩子的右子树上,需要单左旋处理*/
  205. rc.balance = EQUAL_HIGH;
  206. p.balance = EQUAL_HIGH;
  207. break;
  208. case LEFT_HIGH: /**新结点插入到t的右孩子的左子树上,需要双旋处理*/
  209. Node<E> ld = rc.left;
  210. switch(ld.balance){
  211. case LEFT_HIGH:
  212. p.balance = EQUAL_HIGH;
  213. rc.balance = RIGHT_HIGH;
  214. break;
  215. case RIGHT_HIGH:
  216. p.balance = LEFT_HIGH;
  217. rc.balance = EQUAL_HIGH;
  218. break;
  219. case EQUAL_HIGH:
  220. p.balance = EQUAL_HIGH;
  221. rc.balance = EQUAL_HIGH;
  222. break;
  223. }
  224. ld.balance = EQUAL_HIGH;
  225. /**对p的右子树进行右旋处理*/
  226. right_Rotate(p.right);
  227. /**对p进行左旋处理*/
  228. left_Rotate(p);
  229. break;
  230. }
  231. }
  232. /**
  233. * 左旋操作
  234. * p r
  235. * / \ / \
  236. * l r 左旋操作 p rr
  237. * / \ -----------> / \ \
  238. * rl rr l rl rrr
  239. * \
  240. * rrr
  241. * */
  242. private void left_Rotate(Node<E> p) {
  243. if(p != null){
  244. Node<E> r = p.right; /**获得p的右子树的根节点r*/
  245. p.right = r.left; /**将r的左子树转接到p的右子树上*/
  246. if(r.left != null){ /**如果r的左子树不为空,将左子树的父节点设置为p*/
  247. r.left.parent = p;
  248. }
  249. r.parent = p.parent; /**修改r的父节点,修改为p的父节点*/
  250. if(p.parent == null){ /**如果p的父节点为null,那么现在r就是根节点了*/
  251. root = r;
  252. }else if(p == p.parent.left){/**如果p为其父节点的左孩子,将其父节点的左孩子指向r*/
  253. p.parent.left = r;
  254. }else if(p == p.parent.right){/**如果p为其父节点的右孩子,将其父节点的右孩子指向r*/
  255. p.parent.right = r;
  256. }
  257. r.left = p; /**将r的左孩子设置为p*/
  258. p.parent = r; /**将p的父节点设置为r*/
  259. }
  260. }
  261. /**
  262. * 右旋操作
  263. *
  264. * p l
  265. * / \ 右旋操作 / \
  266. * l r -------------> ll p
  267. * / \ / / \
  268. * ll lr lll lr r
  269. * /
  270. * lll
  271. * */
  272. private void right_Rotate(Node<E> p) {
  273. if(p != null){
  274. Node<E> l = p.left; /**获取p的左孩子l*/
  275. p.left = l.right; /**将l的右子树变为p的左子树*/
  276. if(l.right != null){ /**如果l的右子树不为空,将其父节点设置为p*/
  277. l.right.parent = p;
  278. }
  279. l.parent = p.parent; /**将r的父节点修改为p的父节点*/
  280. if(p.parent == null){ /**如果p的父节点为null,即l为root*/
  281. root = l;
  282. }else if(p == p.parent.left){ /**如果p为其父节点的左孩子,将p的父节点的左孩子指向l*/
  283. p.parent.left = l;
  284. }else if(p == p.parent.right){ /**如果p为其父节点的右孩子,将p的父节点的右孩子指向l*/
  285. p.parent.right = l;
  286. }
  287. l.right = p; /**将l的右子树变为p*/
  288. p.parent = l; /**修改p的父节点为l*/
  289. }
  290. }
  291. /**中序非递归方式遍历平衡二叉树*/
  292. public void nrInOrderTraverse(){
  293. Stack<Node<E>> stack = new Stack<Node<E>>();
  294. Node<E> p = root;
  295. while(p != null || !stack.isEmpty()){
  296. while(p != null){
  297. stack.push(p);
  298. p = p.left;
  299. }
  300. p = stack.pop();
  301. System.out.println(p.element);
  302. p = p.right;
  303. }
  304. }
  305. /**平衡二叉树的结点定义*/
  306. class Node<E>{
  307. E element;
  308. /**结点的平衡因子*/
  309. int balance = 0;
  310. /**左孩子结点、右孩子结点、父节点*/
  311. Node<E> left;
  312. Node<E> right;
  313. Node<E> parent;
  314. public Node(){}
  315. public Node(E element, Node<E> parent){
  316. this.element = element;
  317. this.parent = parent;
  318. }
  319. public String toString(){
  320. return element + " BF=" + balance;
  321. }
  322. }
  323. public static void main(String[] args) {
  324. Integer[] num = {5,8,2,0,1, -2, -9, 100};
  325. AVLTree<Integer> avl = new AVLTree<Integer>();
  326. for(int i = 0; i < num.length; i++){
  327. avl.insertElement(num[i]);
  328. }
  329. avl.nrInOrderTraverse();
  330. }
  331. }


 

 

 

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

闽ICP备14008679号