数据结构 - 平衡二叉树

时间:2020-05-28
本文章向大家介绍数据结构 - 平衡二叉树,主要包括数据结构 - 平衡二叉树使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

平衡二叉树是在二叉搜索树的基础上增加了结构变换,理解起来费劲不少。

四种转换类型:LL、RR、RL、LR

要理解这四种类型,需要先说明一个概念:

平衡系数:Balance Fate(以下简称BF)

算法是:拿到一个节点,求这个节点左子树与右子树的深度差的绝对值。

对于平衡二叉树有3种情况:0、1、2,其中2就代表失衡状态,需要转换结构。

从BF为2的节点向下追踪2层,朝着深度深的方向追。就出现了4种情况:

高能预警:

LL:BFnode - BFnode.leftchild - BFnode.leftchild.leftchild (左左)

处理方式:交换BFnode和BFnode.leftchild

RR:BFnode - BFnode.rightchild - BFnode.rightchild.rightchild (右右)

处理方式:交换BFnode和BFnode.rightchild

LR:BFnode - BFnode.leftchild - BFnode.leftchild.rightchild (左右)

处理方式:交换BFnode和BFnode.leftchild.rightchild

RL:BFnode - BFnode.rightchild - BFnode.rightchild.leftchild (右左)

处理方式:交换BFnode和BFnode.rightchild.leftchild

添加元素的思路:

将元素添加到对应位置,向上追溯到根节点,判断当前节点的BF,如果等于2就判断类型,并根据类型进行转换。

删除元素的思路:

找到要删除的节点,再找到删除元素左子树的最右节点(可能不是叶子节点),用最右节点替换要删除的节点,并从最右节点的父节点向上追溯到根节点,判断当前节点的BF,如果等于2就判断类型,并根据类型进行转换。

上代码:(并未经过严格测试,参考网上资料,基于个人理解,供学习使用)

  1 package collections;
  2 
  3 public class AVLTree {
  4 
  5     private AVLNode root;
  6 
  7     // delete node
  8     public void delete(int val) {
  9         if (root == null) {
 10             return;
 11         }
 12         AVLNode delNode = get(val);
 13         if (delNode == null) {
 14             return;
 15         }
 16         AVLNode replaceNode = findRightLeaf(delNode.leftChild);
 17         AVLNode tracebackNode;
 18         // delete node self
 19         // null means left child is null
 20         // contain leaf condition
 21         if (replaceNode == null) {
 22             AVLNode rightChild = delNode.rightChild;
 23             setChild(setParent(rightChild, delNode), delNode, rightChild);
 24             tracebackNode = delNode;
 25         } else {
 26             tracebackNode = replaceDeleteNode(delNode, replaceNode);
 27         }
 28         // trace back to root
 29         tracebackAndConvert(tracebackNode);
 30         // clear delete node
 31         delNode.parent = null;
 32         delNode.leftChild = null;
 33         delNode.rightChild = null;
 34     }
 35 
 36     // check weather the tree has val
 37     public boolean contain(int val) {
 38         return get(val) != null;
 39     }
 40 
 41     // get node by value
 42     public AVLNode get(int val) {
 43         if (root == null) {
 44             return null;
 45         }
 46         return get(val, root);
 47     }
 48 
 49     // add value
 50     public void add(int val) {
 51         if (root == null) {
 52             root = new AVLNode(val);
 53             return;
 54         }
 55         AVLNode insertNode = new AVLNode(val);
 56         AVLNode node = root;
 57         while (true) {
 58             if (val <= node.val) {
 59                 if (node.leftChild == null) {
 60                     insertNode.parent = node;
 61                     node.leftChild = insertNode;
 62                     break;
 63                 }
 64                 node = node.leftChild;
 65             } else {
 66                 if (node.rightChild == null) {
 67                     insertNode.parent = node;
 68                     node.rightChild = insertNode;
 69                     break;
 70                 }
 71                 node = node.rightChild;
 72             }
 73         }
 74         tracebackAndConvert(insertNode);
 75     }
 76 
 77     // degree left right print
 78     public void showDLR() {
 79         iteratorDLR(root);
 80     }
 81 
 82     // left degree right print
 83     public void showLDR() {
 84         iteratorLDR(root);
 85     }
 86 
 87     // left right degree print
 88     public void showLRD() {
 89         iteratorLRD(root);
 90     }
 91 
 92     // check empty
 93     public boolean isEmpty() {
 94         return getDepth(root) == 0;
 95     }
 96 
 97     // get tree depth
 98     public int depth() {
 99         return getDepth(root);
100     }
101 
102     // trace back to root and convert structure
103     private void tracebackAndConvert(AVLNode tracebackNode) {
104         while (true) {
105             if (getBF(tracebackNode) == 2) {
106                 // convert structure
107                 convert(tracebackNode);
108             }
109             if (tracebackNode == root) {
110                 break;
111             }
112             tracebackNode = tracebackNode.parent;
113         }
114     }
115 
116     // convert structure
117     private void convert(AVLNode convertNode) {
118         StringBuilder sign = new StringBuilder();
119         AVLNode node = getNodeAndRotateType(convertNode, sign);
120         switch (sign.toString()) {
121             case "ll":
122                 rotateLL(convertNode);
123                 break;
124             case "rr":
125                 rotateRR(convertNode);
126                 break;
127             case "lr":
128                 rotateLR(node, convertNode);
129                 break;
130             case "rl":
131                 rotateRL(node, convertNode);
132                 break;
133         }
134     }
135 
136     // get node and rotate type
137     private AVLNode getNodeAndRotateType(AVLNode node, StringBuilder sign) {
138         for (int i = 0; i < 2; i++) {
139             // means left child lose balance
140             if (getDepth(node.leftChild) > getDepth(node.rightChild)) {
141                 sign.append('l');
142                 node = node.leftChild;
143             }
144             // means right child lose balance
145             if (getDepth(node.rightChild) > getDepth(node.leftChild)) {
146                 sign.append('r');
147                 node = node.rightChild;
148             }
149         }
150         return node;
151     }
152 
153     // replace delete node
154     private AVLNode replaceDeleteNode(AVLNode deleteNode, AVLNode replaceNode) {
155         AVLNode replaceNodeParent = replaceNode.parent;
156         AVLNode replaceNodeLeftChild = replaceNode.leftChild;
157         if (replaceNodeParent.leftChild == replaceNode) {
158             replaceNodeParent.leftChild = replaceNodeLeftChild;
159         } else {
160             replaceNodeParent.rightChild = replaceNodeLeftChild;
161         }
162         if (replaceNodeLeftChild != null) {
163             replaceNodeLeftChild.parent = replaceNodeParent;
164         }
165         AVLNode deleteParent = deleteNode.parent;
166         AVLNode tracebackNode = replaceNode.parent;
167         replaceNode.parent = deleteParent;
168         if (deleteParent.leftChild == deleteNode) {
169             deleteParent.leftChild = replaceNode;
170         } else {
171             deleteParent.rightChild = replaceNode;
172         }
173         // the replace node is the left child of delete node
174         if (deleteNode.leftChild == replaceNode) {
175             replaceNode.leftChild = null;
176         } else {
177             replaceNode.leftChild = deleteNode.leftChild;
178         }
179         replaceNode.rightChild = deleteNode.rightChild;
180         return tracebackNode;
181     }
182 
183     // find the right leaf which should replace the removed node
184     private AVLNode findRightLeaf(AVLNode node) {
185         if (node == null) {
186             return null;
187         }
188         if (node.rightChild == null) {
189             return node;
190         }
191         return findRightLeaf(node.rightChild);
192     }
193 
194     private AVLNode get(int val, AVLNode node) {
195         if (node == null) {
196             return null;
197         }
198         if (val < node.val) {
199             return get(val, node.leftChild);
200         } else if (val > node.val) {
201             return get(val, node.rightChild);
202         } else {
203             return node;
204         }
205     }
206 
207     private void iteratorDLR(AVLNode node) {
208         if (node == null) {
209             return;
210         }
211         System.out.print(node.val + ",");
212         iteratorDLR(node.leftChild);
213         iteratorDLR(node.rightChild);
214     }
215 
216     private void iteratorLDR(AVLNode node) {
217         if (node == null) {
218             return;
219         }
220         iteratorLDR(node.leftChild);
221         System.out.print(node.val + ",");
222         iteratorLDR(node.rightChild);
223     }
224 
225     private void iteratorLRD(AVLNode node) {
226         if (node == null) {
227             return;
228         }
229         iteratorLRD(node.leftChild);
230         iteratorLRD(node.rightChild);
231         System.out.print(node.val + ",");
232     }
233 
234     // ll rotate
235     private void rotateLL(AVLNode convertNode) {
236         AVLNode node = convertNode.leftChild;
237         setChild(setParent(node, convertNode), convertNode, node);
238         convertNode.leftChild = node.rightChild;
239         node.rightChild = convertNode;
240         convertNode.parent = node;
241     }
242 
243     // rr rotate
244     private void rotateRR(AVLNode convertNode) {
245         AVLNode node = convertNode.rightChild;
246         setChild(setParent(node, convertNode), convertNode, node);
247         convertNode.rightChild = node.leftChild;
248         node.leftChild = convertNode;
249         convertNode.parent = node;
250     }
251 
252     // rl rotate
253     private void rotateRL(AVLNode node, AVLNode convertNode) {
254         setChild(setParent(node, convertNode), convertNode, node);
255         AVLNode rightChild = convertNode.rightChild;
256         rightChild.parent = node;
257         rightChild.leftChild = null;
258         node.leftChild = convertNode;
259         node.rightChild = rightChild;
260         convertNode.parent = node;
261         convertNode.rightChild = null;
262     }
263 
264     // lr rotate
265     private void rotateLR(AVLNode node, AVLNode convertNode) {
266         setChild(setParent(node, convertNode), convertNode, node);
267         AVLNode leftChild = convertNode.leftChild;
268         leftChild.parent = node;
269         leftChild.rightChild = null;
270         node.leftChild = leftChild;
271         node.rightChild = convertNode;
272         convertNode.parent = node;
273         convertNode.leftChild = null;
274     }
275 
276     private AVLNode setParent(AVLNode node, AVLNode convertNode) {
277         AVLNode parent = convertNode.parent;
278         if (node != null) {
279             node.parent = parent;
280         }
281         return parent;
282     }
283 
284     private void setChild(AVLNode parent, AVLNode originChild, AVLNode newChild) {
285         if (parent == null) {
286             root = newChild;
287             return;
288         }
289         if (parent.leftChild == originChild) {
290             parent.leftChild = newChild;
291         } else {
292             parent.rightChild = newChild;
293         }
294     }
295 
296     // get balance fate
297     private int getBF(AVLNode node) {
298         if (node == null) {
299             return 0;
300         }
301         return Math.abs(getDepth(node.leftChild) - getDepth(node.rightChild));
302     }
303 
304     // get node depth
305     private int getDepth(AVLNode node) {
306         if (node == null) {
307             return 0;
308         }
309         return 1 + Math.max(getDepth(node.leftChild), getDepth(node.rightChild));
310     }
311 
312     public static void main(String[] args) {
313         AVLTree tree = new AVLTree();
314         tree.add(25);
315         tree.add(30);
316         tree.add(35);
317         tree.add(45);
318         tree.add(40);
319         tree.add(50);
320         tree.add(47);
321         tree.showDLR();
322         System.out.println();
323         tree.delete(47);
324         tree.showDLR();
325         System.out.println();
326         tree.add(20);
327         tree.showDLR();
328     }
329 
330 }
331 
332 class AVLNode {
333     AVLNode parent;
334     AVLNode leftChild;
335     AVLNode rightChild;
336     int val;
337 
338     public AVLNode(AVLNode parent, AVLNode leftChild, AVLNode rightChild, int val) {
339         this.parent = parent;
340         this.leftChild = leftChild;
341         this.rightChild = rightChild;
342         this.val = val;
343     }
344 
345     public AVLNode(int val) {
346         this.parent = null;
347         this.leftChild = null;
348         this.rightChild = null;
349         this.val = val;
350     }
351 
352 }

原文地址:https://www.cnblogs.com/SamNicole1809/p/12982447.html