新 天 地 代 理-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
今日推荐
周排行