范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

数据结构与算法手撕平衡二叉树

  平衡二叉树定义
  动机:二叉查找树的操作实践复杂度由树高度决定,所以希望控制树高,左右子树尽可能平衡。 平衡二叉树(AVL树):称一棵二叉查找树为高度平衡树,当且仅当或由单一外结点组成,或由两个子树形 Ta 和 Tb 组成,并且满足: |h(Ta) - h(Tb)| <= 1,其中 h(T) 表示树 T 的高度 Ta 和 Tb 都是高度平衡树
  即:每个结点的左子树和右子树的高度最多差 1 的 二叉查找树。 设 T 为高度平衡树中结点 q 的平衡系数为 q 的右子树高度减去左子树高度 高度平衡树所以结点的平衡系数只可能为:-1, 0, 1 结点结构
  1  key:关键字的值
  2  value:关键字的存储信息
  3  height:树的高度(只有一个结点的树的高度为 1)
  4  left:左子树根结点的的引用
  5  right:右子树根结点的引用 复制代码12345678910111213JAVAclass AVLNode, V> {     public K key;     public V value;     public int height;     public AVLNode left;     public AVLNode right;      public AVLNode(K key, V value, int height) {         this.key = key;         this.value = value;         this.height = height;     } } 查找算法
  同二叉查找树的查找算法:【数据结构与算法】手撕二叉查找树 插入算法
  AVL 树是一种二叉查找树,故可以使用二叉查找树的插入方法插入结点,但插入一个新结点时,有可能破坏 AVL 树的平衡性。
  如果发生这种情况,就需要在插入结点后对平衡树进行调整,恢复平衡的性质。实现这种调整的操作称为"旋转"。
  在插入一个新结点 X 后,应调整失去平衡的最小子树,即从插入点到根的路径向上找第一个不平衡结点 A。
  平衡因子 :该结点的左子树高度和右子树高度的差值。如果差值的绝对值小于等于 1,则说明该结点平衡,如果差值的绝对值为 2(不会出现其他情况),则说明该结点不平衡,需要做平衡处理。
  造成结点 A 不平衡的的原因以及调整方式有以下几种情况。 LL 型
  A 结点的平衡因子为 2,说明该结点是最小不平衡结点,需要对 A 结点进行调整。问题发生在 A 结点左子结点的左子结点,所以为 LL 型。
  扁担原理 :右旋 将 A 的左孩子 B 提升为新的根结点; 将原来的根结点 A 降为 B 的右孩子; 各子树按大小关系连接(BL 和 AR 不变,BR 调整为 A 的左子树)。 高度调整:由于调整后 B 的高度依赖于 A 的高度,所以先更新 A 的高度,再更新 B 的高度。 复制代码12345678JAVA    private AVLNode rightRotate(AVLNode a) {         AVLNode b = a.left;         a.left = b.right;         b.right = a;         a.height = Math.max(getHeight(a.left), getHeight(a.right)) + 1;         b.height = Math.max(getHeight(b.left), getHeight(b.left)) + 1;         return b;     } RR 型
  A 结点的平衡因子为 2,说明该结点是最小不平衡结点,需要对 A 结点进行调整。问题发生在 A 结点右子结点的右子结点,所以为 RR 型。
  扁担原理 :左旋 将 A 的右孩子 B 提升为新的根结点; 将原来的根结点 A 降为 B 的左孩子; 各子树按大小关系连接(AL 和 BR 不变,BL 调整为 A 的右子树)。 高度调整:由于调整后 B 的高度依赖于 A 的高度,所以先更新 A 的高度,再更新 B 的高度。 复制代码12345678JAVA    private AVLNode leftRotate(AVLNode a) {         AVLNode b = a.right;         a.right = b.left;         b.left = a;         a.height = Math.max(getHeight(a.left), getHeight(a.right)) + 1;         b.height = Math.max(getHeight(b.left), getHeight(b.left)) + 1;         return b;     } LR 型
  A 结点的平衡因子为 2,说明该结点是最小不平衡结点,需要对 A 结点进行调整。问题发生在 A 结点左子结点的右子结点,所以为 LR 型。
  从旋转的角度:对 B 左旋,然后对 A 右旋 将 B 的左孩子 C 提升为新的根结点; 将原来的根结点 A 降为 C 的右孩子; 各子树按大小关系连接(BL 和 AR 不变,CL 和 CR 分别调整为 B 的右子树和 A 的左子树)。 复制代码1234JAVA    private AVLNode leftRightRotate(AVLNode a) {         a.left = leftRotate(a.left);   // 对 B 左旋         return rightRotate(a);         // 对 A 右旋     } RL 型
  A 结点的平衡因子为 2,说明该结点是最小不平衡结点,需要对 A 结点进行调整。问题发生在 A 结点右子结点的左子结点,所以为 RL 型。
  从旋转的角度:对 B 右旋,然后对 A 左旋 将 B 的左孩子 C 提升为新的根结点; 将原来的根结点 A 降为 C 的左孩子; 各子树按大小关系连接(AL 和 BR 不变,CL 和 CR 分别调整为 A 的右子树和 B 的左子树)。 复制代码1234JAVA    private AVLNode rightLeftRotate(AVLNode a) {         a.right = rightRotate(a.right);         return leftRotate(a);     } 插入方法根结点默认高度为  1 某结点的左右子树高度差的绝对值为  2 ,则需要进行平衡处理 左子树高 key  小于  root.left.key :LL型,进行右旋 key  大于  root.left.key :LR型,进行左右旋 右子树高 key  大于  root.right.key :RR型,进行左旋 key  小于  root.right.key :RR型,进行右左旋 复制代码123456789101112131415161718192021222324252627282930313233JAVA    public void insert(K key, V value) {         root = insert(root, key, value);     }      private AVLNode insert(AVLNode t, K key, V value) {         if (t == null) {             return new AVLNode<>(key, value, 1);         } else if (key.compareTo(t.key) < 0) {             t.left = insert(t.left, key, value);             t.height = Math.max(getHeight(t.left), getHeight(t.right)) + 1;             // 平衡因子判断             if (getHeight(t.left) - getHeight(t.right) == 2) {                 if (key.compareTo(root.left.key) < 0) // 左左:右旋                     t = rightRotate(t);                 else                                 // 左右:先左旋,再右旋                     t = leftRightRotate(t);             }         } else if (key.compareTo(t.key) > 0) {             t.right = insert(t.right, key, value);             t.height = Math.max(getHeight(t.left), getHeight(t.right)) + 1;             // 平衡因子判断             if (getHeight(t.left) - getHeight(t.right) == -2) {                 if (key.compareTo(root.right.key) > 0) // 右右:左旋                     t = leftRotate(t);                 else                                  // 右左:先右旋,再左旋                     t = rightLeftRotate(t);             }         } else {             t.value = value;         }         return t;     }  删除算法概述可采用二叉查找树的删除算法进行删除。
  【数据结构与算法】手撕二叉查找树 删除某结点 X 后,沿从 X 到根节点的路径上考察沿途结点的平衡系数,若第一个不平衡点为 A,平衡以 A 为根的子树。 平衡后,可能使子树 A 高度变小。这样可能导致 A 的父节点不满足平衡性。 所以要继续向上考察结点的平衡性,最远可能至根结点,即最多需要做  O(logn)  次旋转。 对比"插入"操作:平衡 A 后,子树 高度不变 ,A 子树以外的结点不受影响,即插入最多涉及  O(1)  次旋转。 实例分析
  下面举个删除的例子:
  删除以下平衡二叉树中的 16 结点
  1  16 为叶子,将其删除即可,如下图。
  2  指针 g 指向实际被删除节点 16 之父 25,检查是否失衡,25 节点失衡,用 g 、u 、v 记录失衡三代节点(从失衡节点沿着高度大的子树向下找三代),判断为 RL 型,进行 RL 旋转调整平衡,如下图所示。
  3  继续向上检查,指针 g 指向 g 的双亲 69,检查是否失衡,69 节点失衡,用 g 、u 、v 记录失衡三代节点,判断为 RR 型,进行 RR 旋转调整平衡,如下图所示。
  代码
  代码描述 : 若当前结点为空, 则返回该节点 若关键值小于当前结点的关键值,则递归处理该结点的左子树 若关键值大于当前结点的关键值,则递归处理该结点的右子树 若关键值等于当前结点的关键值 若当前结点的左子树为空,则返回该结点的右子树根节点 若当前结点的右子树为空,则返回该结点的左子树根节点 若当前结点左右子树都不为空,则找到该结点的中序前驱结点(该结点左子树的最右结点)或中序后继结点(该结点右子树的最左结点),将其值赋予该结点,然后递归删除中序前驱或后继结点。 更新结点高度 若该结点左子树高度更高,且处于不平衡状态 若为 LL 型,进行右旋 若为 LR 型,先左旋,再右旋 若该结点右子树高度更高,且处于不平衡状态 若为 RL 型,先右旋,再左旋 若我 RR 型,进行左旋 返回该结点 复制代码1234567891011121314151617181920212223242526272829303132333435363738394041424344JAVA    public void remove(K key) {         this.root = delete(root, key);     }      public AVLNode delete(AVLNode t, K key) {         if (t == null) return t;         if (key.compareTo(t.key) < 0) {             t.left = delete(t.left, key);         }         else if (key.compareTo(t.key) > 0) {             t.right = delete(t.right, key);         }         else {             if(t.left == null) return t.right;             else if(t.right == null) return t.left;             else {         // t.left != null && t.right != null                 AVLNode pre = t.left;                 while (pre.right != null) {                     pre = pre.right;                 }                 t.key = pre.key;                 t.value = pre.value;                 t.left = delete(t.left, t.key);             }         }         if (t == null) return t;         t.height = Math.max(getHeight(t.left), getHeight(t.right)) + 1;         if(getHeight(t.left) - getHeight(t.right) >= 2) {             if(getHeight(t.left.left) > getHeight(t.left.right)) {                 return rightRotate(t);             } else {                 return leftRightRotate(t);             }         }         else if(getHeight(t.left) - getHeight(t.right) <= -2) {             if(getHeight(t.right.left) > getHeight(t.right.right)) {                 return rightLeftRotate(t);             }             else {                 return leftRotate(t);             }         }         return t;     } 完整代码复制代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171JAVAclass AVLNode, V> {     public K key;     public V value;     public int height;     public AVLNode left;     public AVLNode right;      public AVLNode(K key, V value, int height) {         this.key = key;         this.value = value;         this.height = height;     } }  class AVLTree, V> {      public AVLNode root;      public int getHeight(AVLNode t) {         return t == null ? 0 : t.height;     }      public void insert(K key, V value) {         root = insert(root, key, value);     }      public void remove(K key) {         this.root = delete(root, key);     }      public AVLNode delete(AVLNode t, K key) {         if (t == null) return t;         if (key.compareTo(t.key) < 0) {             t.left = delete(t.left, key);         }         else if (key.compareTo(t.key) > 0) {             t.right = delete(t.right, key);         }         else {             if(t.left == null) return t.right;             else if(t.right == null) return t.left;             else {         // t.left != null && t.right != null                 AVLNode pre = t.left;                 while (pre.right != null) {                     pre = pre.right;                 }                 t.key = pre.key;                 t.value = pre.value;                 t.left = delete(t.left, t.key);             }         }         if (t == null) return t;         t.height = Math.max(getHeight(t.left), getHeight(t.right)) + 1;         if(getHeight(t.left) - getHeight(t.right) >= 2) {             if(getHeight(t.left.left) > getHeight(t.left.right)) {                 return rightRotate(t);             } else {                 return leftRightRotate(t);             }         }         else if(getHeight(t.left) - getHeight(t.right) <= -2) {             if(getHeight(t.right.left) > getHeight(t.right.right)) {                 return rightLeftRotate(t);             }             else {                 return leftRotate(t);             }         }         return t;     }       private AVLNode insert(AVLNode t, K key, V value) {         if (t == null) {             return new AVLNode<>(key, value, 1);         }         if (key.compareTo(t.key) < 0) {             t.left = insert(t.left, key, value);             // 平衡因子判断             if (getHeight(t.left) - getHeight(t.right) == 2) {                 if (key.compareTo(t.left.key) < 0) // 左左:右旋                     t = rightRotate(t);                 else                                  // 左右:先左旋,再右旋                     t = leftRightRotate(t);             }         } else if (key.compareTo(t.key) > 0) {             t.right = insert(t.right, key, value);             // 平衡因子判断             if (getHeight(t.left) - getHeight(t.right) == -2) {                 if (key.compareTo(t.right.key) > 0) // 右右:左旋                     t = leftRotate(t);                 else                                   // 右左:先右旋,再左旋                     t = rightLeftRotate(t);             }         } else {             t.value = value;         }         t.height = Math.max(getHeight(t.left), getHeight(t.right)) + 1;         return t;     }      private AVLNode rightLeftRotate(AVLNode a) {         a.right = rightRotate(a.right);         return leftRotate(a);     }      private AVLNode leftRightRotate(AVLNode a) {         a.left = leftRotate(a.left);         return rightRotate(a);     }      private AVLNode leftRotate(AVLNode a) {         AVLNode b = a.right;         a.right = b.left;         b.left = a;         a.height = Math.max(getHeight(a.left), getHeight(a.right)) + 1;         b.height = Math.max(getHeight(b.left), getHeight(b.right)) + 1;         return b;     }      private AVLNode rightRotate(AVLNode a) {         AVLNode b = a.left;         a.left = b.right;         b.right = a;         a.height = Math.max(getHeight(a.left), getHeight(a.right)) + 1;         b.height = Math.max(getHeight(b.left), getHeight(b.right)) + 1;         return b;     }      private void inorder(AVLNode root) {         if (root != null) {             inorder(root.left);             System.out.print("(key: " + root.key + " , value: " + root.value + " , height: " + root.height + ") ");             inorder(root.right);         }     }      private void preorder(AVLNode root) {         if (root != null) {             System.out.print("(key: " + root.key + " , value: " + root.value + " , height: " + root.height + ") ");             preorder(root.left);             preorder(root.right);         }     }      private void postorder(AVLNode root) {         if (root != null) {             postorder(root.left);             postorder(root.right);             System.out.print("(key: " + root.key + " , value: " + root.value + " , height: " + root.height + ") ");         }     }      public void postorderTraverse() {         System.out.print("后序遍历:");         postorder(root);         System.out.println();     }      public void preorderTraverse() {         System.out.print("先序遍历:");         preorder(root);         System.out.println();     }      public void inorderTraverse() {         System.out.print("中序遍历:");         inorder(root);         System.out.println();     } }
  方法测试 复制代码1234567891011121314151617181920JAVA    public static void main(String[] args) {         AVLTree tree = new AVLTree<>();         tree.insert(69, 1);         tree.insert(25, 1);         tree.insert(80, 1);         tree.insert(16, 1);         tree.insert(56, 1);         tree.insert(75, 1);         tree.insert(90, 1);         tree.insert(30, 1);         tree.insert(78, 1);         tree.insert(85, 1);         tree.insert(98, 1);         tree.insert(82, 1);          tree.remove(16);         tree.preorderTraverse();         tree.inorderTraverse();         tree.postorderTraverse();     }
  输出 复制代码123JAVA先序遍历:(key: 80 , value: 1 , height: 4) (key: 69 , value: 1 , height: 3) (key: 30 , value: 1 , height: 2) (key: 25 , value: 1 , height: 1) (key: 56 , value: 1 , height: 1) (key: 75 , value: 1 , height: 2) (key: 78 , value: 1 , height: 1) (key: 90 , value: 1 , height: 3) (key: 85 , value: 1 , height: 2) (key: 82 , value: 1 , height: 1) (key: 98 , value: 1 , height: 1)  中序遍历:(key: 25 , value: 1 , height: 1) (key: 30 , value: 1 , height: 2) (key: 56 , value: 1 , height: 1) (key: 69 , value: 1 , height: 3) (key: 75 , value: 1 , height: 2) (key: 78 , value: 1 , height: 1) (key: 80 , value: 1 , height: 4) (key: 82 , value: 1 , height: 1) (key: 85 , value: 1 , height: 2) (key: 90 , value: 1 , height: 3) (key: 98 , value: 1 , height: 1)  后序遍历:(key: 25 , value: 1 , height: 1) (key: 56 , value: 1 , height: 1) (key: 30 , value: 1 , height: 2) (key: 78 , value: 1 , height: 1) (key: 75 , value: 1 , height: 2) (key: 69 , value: 1 , height: 3) (key: 82 , value: 1 , height: 1) (key: 85 , value: 1 , height: 2) (key: 98 , value: 1 , height: 1) (key: 90 , value: 1 , height: 3) (key: 80 , value: 1 , height: 4) 本文作者:gonghr
  本文链接:https://www.cnblogs.com/gonghr/p/16064797.html

童文红在马云身边21年,从前台小妹变阿里总裁,每月拿500万薪资阿里巴巴作为大众熟知的互联网企业,在2020年其一年的营收就超过了7000亿,在国内民营企业当中也名列前茅,马云也凭借阿里巴巴的快速发展,曾荣登中国首富之位。但实际上阿里巴巴在19哪家厂商生产的曲面屏手机最好看?论工艺技术方面,华为,三星和vivo都很不错,但要说感觉,它们之间还是有一定的区别的,华为手机更显高端,给人的感觉它适合中年纪偏大的商务人士使用,而三星虽然是曲面屏的鼻祖,但在配色黑色星期五黑马产品当属Switch莫属今天是黑色星期五,不少小伙伴们已经准备好海淘的商品了,有没有考虑过给自己的家里买一个健身环当做娱乐工具呢?近日,Nintendo官方在油管上公布了美国女星杰西卡阿尔芭出演的任天堂S大家觉得联想事件后续会怎么发展?所有涉事人员会一网打尽。会受到严惩。我感觉,如果联想被诟病的问题只是在道德层面的伤害民族感情的问题,可能不会持续成为热点,也没有人会被追究法律责任如果联想的问题涉及到违法,比如放高支持健康关怀,父母用也贴心,华为WATCHGT3上手体验在外工作的你心里最惦记的是什么?我想应该是远方的父母吧!我们逐渐长大成人,父母却在慢慢变老,人一旦年纪大了,身体机能就会急速下降,各种慢性疾病也会找上门来。不能够陪伴父母身边,最担不是华为小米!搭载国产芯片,全球销量夺冠的手机是哪款?根据市场调研机构IDC公布全球追踪报告显示,有一款手机搭载国产芯片,截至今年6月份全球销量突破2亿台,9月份更是持续蝉联全球销量第一,国行版本售价只需一二百块,手机既不属于华为更不在中国做假账,到美国不交账,贾跃亭给美国人上了一课?11月26日,滞美不归的贾跃亭收到了纳斯达克的退市警告,距离法拉第上市仅四个月零三天。理由是法拉第没有按照规定提交第三季度的财务报告。本以为贾跃亭到了美国,慑于美国股市严格的监管,国家计算机病毒应急处理中心监测发现十七款违法移动应用新华社天津11月27日电(记者张建新)国家计算机病毒应急处理中心近期通过互联网监测发现17款移动应用存在隐私不合规行为,违反网络安全法个人信息保护法相关规定,涉嫌超范围采集个人隐私下月发布一款小米的小屏旗舰手机,6。28英寸是你期待的小屏吗?前一段时间,关于小米12即将首发搭载骁龙898在12月发布的消息已经爆出,而最近,关于一款小米12系列的小屏旗舰手机也将要发布的消息被爆料。这款手机的命名不是小米12mini,而是华为科普芯片设计制造全流程来源内容来自华为麒麟,谢谢。由沙成芯,方寸之间。指尖大小的芯片,内含153亿个晶体管。如此复杂的工艺是如何实现的?漫解麒麟芯片的内芯世界!本期的问题是1芯片的设计与制造过程可以分为没有宽带也能有WiFi的路由器,蒲公英X4C测评大家都知道,WiFi是个好东西,只要手机连上它,就能畅快的上网。但是WiFi是无线路由器发出的信号,而路由器则需要有宽带的接入才能提供网络连接。而在一些不太方便连接网线的地方,比如
如何进行伪原创创作,有什么工具吗?长期需要输入文章,可有时写作却找不到灵感,真的很尴尬,这个时候就可以找个伪原创工具来一键搞定了,今天就来说说,好多自媒体人们用的几个的写作软件,功能强大,适用于工作和学习的方方面面最新性价比手机推荐20003000New最新性价比手机推荐20003000价位全文无GUANG,放心食用续航与发热状况中图2为wAYLAB的真机实测排行,涵盖绝大部分主流手机2k2。5k旗舰级(OPPO旗下)rea你拍摄过晚霞吗?相机应该怎么设置?回答您的问题晚霞场景是大多数摄影爱好者喜欢热爱和追逐的美景,特别是具有云彩特异的天空,再配合较好的主体或前景,通过精心构图和恰当的相机设置就能给画面创造美丽壮观震撼的场景。但相机的走街串巷挑卖,不如结合电商模式农产品电商城市还是你以为的城市,农村却不是你以为的农村了。一说起农村,人们印象中似乎都是贫困落后。但近来年,随着农村经济的发展,农村电商市场正在成为香饽饽。农村电商总体上可分为两种如何正确地清理C盘垃圾且不影响系统?小伙伴们,今日愉快!小伙伴们,对于C盘垃圾该如何清理且不影响系统呢?C盘是电脑中比较重要的一个存储盘,如果C盘的文件太多,就会影响到电脑的运行速度,如果不想电脑变卡,就需要对电脑进大家敢不敢把手机里最好看的摄影相片分享出来给大家欣赏啊?无题全部都是手机拍摄。今年11月初拍的。地点嘛大家猜猜看耶耶耶没有最好,只有更好,不知道我这张家门口的照片算不算是好照片。用小米手机拍摄。天平红枫甲天下?!耶大家觉得这花拍得怎么样离开中国玩不转,荷兰ASML公司继续发货光刻机,是无奈的选择吗?说到芯片的重要性,在一般人眼里,以为只是手机电脑等产品需要用到芯片,实际上,芯片应用范围非常广,不论是军事,还是民用,几乎所有的电子终端设备都要用到芯片,比如家电汽车航天通信等等行恒大汽车以231万美元卖出旗下电机业务2019年买入价格为5亿高质量能源内容,点击右上角加关注11月15日,据和讯汽车报道,英国电机制造商Saietta集团在11日表示,将从恒大集团旗下汽车子公司手中收购电动传动系统公司eTraction,交猎物基本已经死亡某电商平台疑售卖非法猎捕工具,平台客服核实属实会严肃处理某电商平台商家疑似售卖非法猎捕工具,引起民间动物保护志愿者的注意。11月15日,志愿者王明(化名)告诉新京报记者,他们发现该平台有多位商家售卖鸟网猎夹猎套以及电捕装置等,且商品描述三年亏掉200亿,烧出中国AI独角兽,拿下70余项全球冠军文JING审核子扬校正知秋业界一般将人工智能发展分为三个阶段上世纪50年代到80年代,属于起步期80年代到21世纪初期,为探索期。而2006年至今,则是快速成长期。在此期间,AI创高清广角双摄10。7亿色触控屏加持,荣耀MagicBookV14体验如何?曾经一段视频触动了很多职场打工人的神经,一名女生连续加班半个月,生日当天下班路上又被要求回公司加班,压力之下,瞬间情绪崩溃伤心痛哭。的确,成年人的世界从来都没有容易两个字。人在职场