ds查找—二叉树平衡因子_面试官让我手写一个平衡二叉树,我当时就笑了
平衡二叉樹對于初學者一直是一個比較復雜的知識點,因為其里面涉及到了大量的旋轉操作。把大量的同學都給轉暈了。這篇文章最主要的特點就是通過動畫的形式演示。確保大家都能看懂。最后是手寫一個平衡二叉樹。
一、概念
平衡二叉樹是外國的兩個大爺發明的。一開始發明的是二叉查找樹。后來覺得不給力演化成了平衡二叉樹。那什么是二叉查找樹呢?我們給出一張圖來看看:
看到這張圖我們就會發現如下的特征。從每個節點出發,左邊的節點一定小于右邊的。但是你會發現這可以高低不平,看起來很不美觀。于是慢慢的演化成了平衡二叉樹。(當然不是因為美觀演化的)。也就是說平衡二叉樹的前提就是一顆二叉查找樹
平衡二叉樹定義(AVL):(1)它的左子樹和右子樹的深度之差(平衡因子)的絕對值不超過1,(2)它的左子樹和右子樹都是一顆平衡二叉樹。也就是說以上兩條規則,只要破壞了一個就不是平衡二叉樹了。比如說下面這張圖。
上面這張圖就是破壞了二叉查找樹這一條規則。當然了還有一條規則。也就是他的高度只差不能超過1.
現在相信我們已經明白了什么是平衡二叉樹。下面我們就來看看平衡二叉樹的增刪改查操作是怎么樣的。
二、平衡二叉樹的插入操作
我們先從最簡單的入手,一步一步來。
1、右旋
首先我們插入幾個數字,50,45,44。通過動畫我們來演示一遍
(1)插入50根節點不會出現任何操作
(2)插入45,往左邊插入即可
(3)插入44,破壞了平衡,于是右旋。
2、左旋
我們插入幾個數字,50,60,70。通過動畫我們來演示一遍
(1)插入50根節點不會出現旋轉
(2)插入60,往右邊插入即可
(3)插入70,破壞了平衡,于是左旋。
3、先右旋再左旋
我們依次插入50,60,55.通過動畫我們演示一遍
(1)插入55,根節點,不會出現旋轉
(2)插入60,往右邊插入
(3)插入55,破壞了平衡,于是先把55和60右旋,然后整體左旋。
4、先左旋后右旋
我們依次插入50,40,45.通過動畫我們演示一遍。
(1)插入55,根節點,不會出現旋轉
(2)插入40,往左邊插入
(3)插入45,破壞了平衡,于是先把45和40左旋,然后整體右旋。
現在我們基本上已經把插入的幾種情況羅列出來了。現在我們畫一張圖,來一個總結。
上圖對于每一種情況,從上往下看就好了。對于平衡二叉樹的刪除操作,其實也是同樣的道理,找到相應的元素之后,對其進行刪除,刪除之后如果破壞了平衡,只需要按照上面的這幾種情況進行調整即可。下面我們來分析一下平衡二叉樹的查找操作。
三、平衡二叉樹的查找
平衡二叉樹的查找很簡單,只需要按照二叉查找樹的順序執行就好。我們使用一張動畫演示一下:
現在平衡二叉樹的操作相信你已經能夠理解。下面我們就來關注最后一個問題,那就是如何手寫一顆平衡二叉樹呢?
四、手寫一顆平衡二叉樹
平衡二叉樹的代碼操作,難點在于旋轉。只要把旋轉弄清楚基本上整個樹就能完成了,根據上面旋轉的特點我們從零開始定義一顆。
第一步:定義節點
public class AVLNode {public int data;//保存節點數據public int depth;//保存節點深度public int balance;//是否平衡public AVLNode parent;//指向父節點public AVLNode left;//指向左子樹public AVLNode right;//指向右子樹 ?public AVLNode(int data){this.data = data;depth = 1;balance = 0;left = null;right = null;}}第二步:插入數據
public void insert(AVLNode root, int data){//如果說插入的數據小于根節點,往左邊遞歸插入if (data < root.data){if (root.left != null){insert(root.left, data);}else {root.left = new AVLNode(data);root.left.parent = root;}}//如果說插入的數據小于根節點,往左邊遞歸插入else {if (root.right != null){insert(root.right, data);}else {root.right = new AVLNode(data);root.right.parent = root;}}//插入之后,計算平衡銀子root.balance = calcBalance(root);// 左子樹高,應該右旋if (root.balance >= 2){// 右孫高,先左旋if (root.left.balance == -1){left_rotate(root.left);}right_rotate(root);}// 右子樹高,左旋if (root.balance <= -2){// 左孫高,先右旋if (root.right.balance == 1){right_rotate(root.right);}left_rotate(root);}//調整之后,重新計算平衡因子和樹的深度root.balance = calcBalance(root);root.depth = calcDepth(root); }第三步:左旋和右旋的調整
1、右旋
// 右旋private void right_rotate(AVLNode p){// 一次旋轉涉及到的結點包括祖父,父親,右兒子AVLNode pParent = p.parent;AVLNode pLeftSon = p.left;AVLNode pRightGrandSon = pLeftSon.right;// 左子變父pLeftSon.parent = pParent;if (pParent != null){if (p == pParent.left){pParent.left = pLeftSon;}else if (p == pParent.right){pParent.right = pLeftSon;}}pLeftSon.right = p;p.parent = pLeftSon;// 右孫變左孫p.left = pRightGrandSon;if (pRightGrandSon != null){pRightGrandSon.parent = p;}p.depth = calcDepth(p);p.balance = calcBalance(p);pLeftSon.depth = calcDepth(pLeftSon);pLeftSon.balance = calcBalance(pLeftSon);}2、左旋
private void left_rotate(AVLNode p){// 一次選擇涉及到的結點包括祖父,父親,左兒子AVLNode pParent = p.parent;AVLNode pRightSon = p.right;AVLNode pLeftGrandSon = pRightSon.left;// 右子變父pRightSon.parent = pParent;if (pParent != null){if (p == pParent.right){pParent.right = pRightSon;}else if (p == pParent.left){pParent.left = pRightSon;}}pRightSon.left = p;p.parent = pRightSon;// 左孫變右孫p.right = pLeftGrandSon;if (pLeftGrandSon != null){pLeftGrandSon.parent = p;}p.depth = calcDepth(p);p.balance = calcBalance(p);pRightSon.depth = calcDepth(pRightSon);pRightSon.balance = calcBalance(pRightSon);}第四步:計算平衡和深度
1、計算平衡
public int calcBalance(AVLNode p){int left_depth;int right_depth;//左子樹深度if (p.left != null){left_depth = p.left.depth;}else {left_depth = 0;}//右子樹深度if (p.right != null){right_depth = p.right.depth;}else {right_depth = 0;}return left_depth - right_depth;}2、計算深度
public int calcDepth(AVLNode p){int depth = 0;if (p.left != null){depth = p.left.depth;}if (p.right != null && depth < p.right.depth){depth = p.right.depth;}depth++;return depth;}看起來代碼有些多,其實梳理一下就不多了。
(1)首先定義一個節點,里面有get和set方法,構造函數等等做準備工作
(2)直接寫業務流程,比如說這里的insert操作,里面涉及到的旋轉操作先用方法代替
(3)對主業務流程的操作,缺哪一個方法,寫哪一個方法即可
總結
以上是生活随笔為你收集整理的ds查找—二叉树平衡因子_面试官让我手写一个平衡二叉树,我当时就笑了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用 cglib_CGLib 动态代理
- 下一篇: bp神经网络pid控制_文章推荐 | B