新 天 地 代 理

  新 天 地 代 理-qQ同步【2668777777】信誉至上【待遇,一步到位】直接添加无需打开.AVL树是一种高度平衡的二叉搜索树,其命名源自于联合发明算法的三位科学家的名字的首字母。此处“平衡”的定义是:任意节点的左右子树的高度相差不超过1。有了这个平衡的性质,使得AVL树的高度H总是接近log(N),因此各种增删改查的操作的复杂度能够保证在对数级别。没有bad case是AVL树与普通的二叉搜索树的最大区别。为了实现平衡性质,我们需要记录每个节点的高度(或者平衡因子)来检测不平衡的情况。为了修正高度不平衡,需要用到“旋转”的方法,分为单旋转和双旋转,左右总共四种旋转。下面的图解会给出旋转的示意,这个是AVL树的关键算法。AVL树看起来特简单,但你动手写写就知实现一棵AVL树有多麻烦。如果你能用200行写出能增删改查的AVL树,请留言给我点提示。我花了一天想思路,并犹豫要不要放弃。又花了一天写代码和自测。终于用500多行代码写完了自己的第一棵AVL树。如果面试里需要平衡查找结构,你最好试试树堆或者跳表,千万别想AVL或者伸展树。不需要自己写的话,还是<map>吧。
  
  图示:
  
  一棵平衡的二叉树:
  
  查找不涉及数据的修改,因此和普通二叉搜索树完全一样:
  
  插入21之后,树的平衡被破坏了,而且不止一个点出现了不平衡:
  
  当平衡被破坏之后,需要从第一个不平衡的地方开始旋转,然后逐层往上继续修正。此处给出一次旋转之后的结果:
  
  一次旋转不一定能修复N个不平衡的节点,因此要从第一个不平衡的节点往上检查所有需要修复的节点。
  
  新 天 地 代 理-qQ同步【2668777777】信誉至上【待遇,一步到位】直接添加无需打开.下面给出四种旋转的示意图,代码的注释中也有类似的示意,以便读者能够直观地想象旋转中发生的变形(数据结构最大的魅力,就在于它们动起来比变形金刚的花样还多)。
  
  实现:
  
  为了向上检查,我引入了parent指针指向二叉树节点的父节点。为了检查平衡状况,我是用了height成员表示树的高度。虽然平衡因子好像更规范,但当时尝试用平衡因子的时候思路始终理不清楚,所以选择了高度作为依据。下面的实现中其实有不少代码是供测试用的,比如三种遍历。这些debug代码对于学习AVL树有帮助作用,如果你有兴趣可以自己运行查看结果。
  
  插入和删除都会影响树的平衡性,因此对于发生变动的节点,需要更新其高度,以便检测平衡性并进行旋转。AVL树的删除挺难想的,需要在草稿纸上比划半天才能想明白。
  
  请看代码。
  
  1 // My implementation for avl tree.
  
  2 #include <iostream>
  
  3 #include <string>
  
  4 #include <vector>
  
  5 using namespace std;
  
  6
  
  7 struct TreeNode {
  
  8 int val;
  
  9 int height;
  
  10 TreeNode *left;
  
  11 TreeNode *right;
  
  12 TreeNode *parent;
  
  13 TreeNode(int _val): val(_val), height(1), left(nullptr), right(nullptr), parent(nullptr) {};
  
  14 };
  
  15
  
  16 class AVLTree {
  
  17 public:
  
  18 AVLTree() {
  
  19 m_root = nullptr;
  
  20 }新 天 地 代 理-qQ同步【2668777777】信誉至上【待遇,一步到位】直接添加无需打开.

猜你喜欢

转载自www.cnblogs.com/huhz1979/p/12791343.html