【愚公系列】2021年11月 C#版 数据结构与算法解析(AVL树)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 【愚公系列】2021年11月 C#版 数据结构与算法解析(AVL树)

AVL树定义:在计算机科学中,AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。AVL树得名于它的发明者G. M. Adelson-Velsky和E. M. Landis,他们在1962年的论文《An algorithm for the organization of information》中发表了它。

平衡二叉树是带有平衡条件的二叉查找树,指的是空树或者任一结点左、右高度差的绝对值不超过1的二叉树.适合用于插入删除次数比较少,但查找多的情况。

比如:

image.png

实现的难点在于,二叉树的平衡旋转

分为四种旋转,RR、LL、LR、RL旋转

RR旋转

image.png

麻烦结点在发现者右子树的右边,所以叫RR插入,需要RR旋转

LL旋转

image.png

麻烦结点在发现者左子树的左边,所以叫LL插入,需要LL旋转

LR旋转

image.png

RL旋转

image.png

C#实现源码

public class Bit : IComparable<Bit>
{
    public int Value;
    public Bit(int value) => Value = value;
    public int CompareTo(Bit other) => Value - other.Value;
}
public class AvlTreeNote<TKey> where TKey : IComparable<TKey>
{
    public TKey Key;
    public int Height;
    public AvlTreeNote<TKey> LChild;
    public AvlTreeNote<TKey> RChild;
    public AvlTreeNote(TKey key, AvlTreeNote<TKey> lChild, AvlTreeNote<TKey> rChild)
    {
        Key = key;
        LChild = lChild;
        RChild = rChild;
    }
}
public class AvlTree<TKey> where TKey : IComparable<TKey>
{
    public AvlTreeNote<TKey> Root;          // 根节点
    private bool _isBalance;                // 标志是否平衡过二叉树
    /// <summary>
    /// 插入节点
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public AvlTreeNote<TKey> Insert(TKey key) => Root = Insert(key, Root);
    /// <summary>
    /// 插入到指定节点下
    /// </summary>
    /// <param name="key"></param>
    /// <param name="node"></param>
    /// <returns></returns>
    private AvlTreeNote<TKey> Insert(TKey key, AvlTreeNote<TKey> node)
    {
        if (node == null)
        {
            node = new AvlTreeNote<TKey>(key, null, null);
        }
        else
        {
            // 如果树里已经存在该节点,直接返回为null
            if (key.CompareTo(node.Key) == 0) return null;
            if (key.CompareTo(node.Key) < 0)
            {
                // 应该在左树进行搜索插入
                node.LChild = Insert(key, node.LChild);
                if (node.LChild == null) return node;
                switch (node.Height)
                {
                    case 1:
                        return LeftBalance(node);
                    case 0:
                        node.Height = _isBalance ? 0 : 1;
                        break;
                    case -1:
                        node.Height = 0;
                        break;
                }
            }
            else
            {
                // 应该在右树进行搜索插入
                node.RChild = Insert(key, node.RChild);
                if (node.RChild == null) return node;
                switch (node.Height)
                {
                    case 1:
                        node.Height = 0;
                        break;
                    case 0:
                        node.Height = _isBalance ? 0 : -1;
                        break;
                    case -1:
                        return RightBalance(node);
                }
            }
        }
        _isBalance = false;
        return node;
    }
    /// <summary>
    /// 左树平衡处理
    /// </summary>
    /// <param name="node"></param>
    private AvlTreeNote<TKey> LeftBalance(AvlTreeNote<TKey> node)
    {
        if (_isBalance) return node;
        var leftNode = node.LChild;
        switch (leftNode.Height)
        {
            case 1:
                node.Height = leftNode.Height = 0;
                node = R_Rotate(node);
                break;
            case -1:
                node.Height = leftNode.Height = 0;
                node.LChild = L_Rotate(leftNode);
                node = R_Rotate(node);
                break;
        }
        return node;
    }
    private AvlTreeNote<TKey> RightBalance(AvlTreeNote<TKey> node)
    {
        if (_isBalance) return node;
        var rightNode = node.RChild;
        switch (rightNode.Height)
        {
            case -1:
                node.Height = rightNode.Height = 0;
                node = L_Rotate(node);
                break;
            case 1:
                node.Height = rightNode.Height = 0;
                node.RChild = R_Rotate(rightNode);
                node = L_Rotate(node);
                break;
        }
        return node;
    }
    /// <summary>
    /// 右旋操作
    /// </summary>
    /// <param name="node"></param>
    private AvlTreeNote<TKey> R_Rotate(AvlTreeNote<TKey> node)
    {
        var temp = node.LChild;
        node.LChild = temp.RChild;
        temp.RChild = node;
        _isBalance = true;
        return temp;
    }
    /// <summary>
    /// 左旋操作
    /// </summary>
    /// <param name="node"></param>
    private AvlTreeNote<TKey> L_Rotate(AvlTreeNote<TKey> node)
    {
        var temp = node.RChild;
        node.RChild = temp.LChild;
        temp.LChild = node;
        _isBalance = true;
        return temp;
    }
    /// <summary>
    /// 查找二叉树
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public AvlTreeNote<TKey> Find(TKey key) => Find(key, Root);
    /// <summary>
    /// 查找二叉树
    /// </summary>
    /// <param name="key"></param>
    /// <param name="node"></param>
    /// <returns></returns>
    public AvlTreeNote<TKey> Find(TKey key, AvlTreeNote<TKey> node)
    {
        if (node == null) return null;
        if (key.CompareTo(node.Key) < 0)
        {
            node = Find(key, node.LChild);
        }
        else if (key.CompareTo(node.Key) > 0)
        {
            node = Find(key, node.RChild);
        }
        return node;
    }
    /// <summary>
    /// 用于删除该节点移动节点
    /// </summary>
    /// <param name="node"></param>
    /// <param name="findNode"></param>
    /// <returns></returns>
    private AvlTreeNote<TKey> Move(AvlTreeNote<TKey> node, AvlTreeNote<TKey> findNode)
    {
        AvlTreeNote<TKey> moveNode;
        if (findNode != null)
        {
            if (findNode.RChild != null)
            {
                moveNode = findNode.RChild;
                findNode.RChild = null;
            }
            else
            {
                findNode.LChild = null;
                moveNode = findNode;
            }
            if (node.LChild != moveNode) moveNode.LChild = node.LChild;
            if (node.RChild != moveNode) moveNode.RChild = node.RChild;
        }
        else
        {
            moveNode = null;
        }
        node.LChild = null;
        node.RChild = null;
        node.Key = default(TKey);
        node.Height = 0;
        return moveNode;
    }
    /// <summary>
    /// 删除节点
    /// </summary>
    /// <param name="key"></param>
    public void Remove(TKey key) => Root = Remove(key, Root);
    private AvlTreeNote<TKey> Remove(TKey key, AvlTreeNote<TKey> node)
    {
        if (node == null) return null;
        if (key.CompareTo(node.Key) < 0)
        {
            if (node.LChild == null) return node;
            node.LChild = Remove(key, node.LChild);
            switch (node.Height)
            {
                case 1:
                    node.Height = 0;
                    break;
                case 0:
                    node.Height = -1;
                    break;
                case -1:
                    // 要进行旋转
                    node.Height = 0;
                    return node.LChild == null ? RightBalance(node) : LeftBalance(node);
            }
        }
        else if (key.CompareTo(node.Key) > 0)
        {
            if (node.RChild == null) return node;
            node.RChild = Remove(key, node.RChild);
            switch (node.Height)
            {
                case 1:
                    // 要进行旋转
                    node.Height = 0;
                    return node.RChild == null ? LeftBalance(node) : RightBalance(node);
                    break;
                case 0:
                    node.Height = 1;
                    break;
                case -1:
                    node.Height = 0;
                    break;
            }
        }
        else if (key.CompareTo(node.Key) == 0)
        {
            var findNode = Remove(key, node.LChild);
            node = Move(node, findNode);
        }
        _isBalance = false;
        return node;
    }
}

C/C++实现

#include <stack>//栈
#include <queue>
#include <iostream>
#include <initializer_list>
using namespace std;
template <typename Comparable>
class AVLTree
{
private:
  static const int ALLOWED_IMBLANCE = 1;
  struct AVLNode
  {
    Comparable element;
    AVLNode * left;
    AVLNode * right;
    int height;
    AVLNode(const Comparable & theElement, AVLNode *lt, AVLNode *rt,int h = 0)
      :element(theElement), left(lt), right(rt),height(h) {}
    AVLNode(Comparable && theElement, AVLNode *lt, AVLNode *rt, int h = 0)
      :element(std::move(theElement)), left(lt), right(rt),height(h) {}
  };
  AVLNode * root;
  void Insert(const Comparable &x, AVLNode * & t);
  void Insert(Comparable && x, AVLNode *&t);
  void Insert(initializer_list<Comparable> &d, AVLNode *& t);
  void Remove(const Comparable &x, AVLNode *&t);
  AVLNode * findMin(AVLNode *t)const;
  AVLNode * findMax(AVLNode *t)const;
  bool contains(const Comparable &x, AVLNode *t) const;
  void makeEmpty(AVLNode * &t);
  void PrintTree(AVLNode *t) const;
  AVLNode* clone(AVLNode *t)const
  {
    if (t == nullptr)
      return nullptr;
    return new AVLNode(t->element, clone(t->left), clone(t->right));
  }
  void rotateWithLeftChild(AVLNode *& k2);
  void rotateWithRightChild(AVLNode *& k2);
  void doubleWithLeftChild(AVLNode *&k3);
  void doubleWithRightChild(AVLNode *&k3);
  void balance(AVLNode*& t);
public:
  AVLTree() :root(nullptr) {}
  AVLTree(const AVLTree & rhs) :root(nullptr) { root = clone(rhs.root); }
  AVLTree(AVLTree && rhs) :root(nullptr) {  root = rhs.root;rhs = nullptr;}
  ~AVLTree() { makeEmpty(); }
  const Comparable & findMin() const { return findMin(root)->element; }
  const Comparable & findMax() const { findMax(root)->element; }
  bool contains(const Comparable & x) const { return contains(x, root); }
  bool isEmpty() const { return root == nullptr; }
  int height(AVLNode *t) const { return t == nullptr ? -1 : t->height; }
  void PrintTree()const { PrintTree(root); }
  void makeEmpty() { makeEmpty(root); }
  void Insert(const Comparable &x) { Insert(x,root); }
  void Insert(Comparable && x) { Insert(x,root); }
  void Insert(initializer_list<Comparable>d) { Insert(d, root); }
  void Remove(const Comparable &x) { Remove(x, root); }
  AVLTree & operator=(const AVLTree & rhs)
  {
    if (this != &rhs)
    {
      makeEmpty();
      root = clone(rhs.root);
    }
    return *this;
  }
  AVLTree & operator=(AVLTree && rhs)
  {
    if (this != &rhs)
    {
      makeEmpty();
      root = rhs.root;
      rhs.root = nullptr;
    }
    return *this;
  }
  friend int Max(int a, int b);
};
int Max(int a, int b)
{
  return (a > b) ? a : b;
}
template<typename Comparable>
void AVLTree<Comparable>::Insert(const Comparable & x, AVLNode *& t)
{
  if (t == nullptr)
  {
    t = new AVLNode(x, nullptr, nullptr);
  }
  else if (x < t->element)
    Insert(x, t->left);
  else if (t->element < x)
    Insert(x, t->right);
  balance(t);
}
template<typename Comparable>
void AVLTree<Comparable>::Insert(Comparable && x, AVLNode *& t)
{
  if (t == nullptr)
  {
    t = new AVLNode(std::move(x), nullptr, nullptr);
  }
  else if (x < t->element)
    Insert(std::move(x), t->left);
  else if (t->element < x)
    Insert(std::move(x), t->right);
  balance(t);
}
template<typename Comparable>
void AVLTree<Comparable>::Insert(initializer_list<Comparable> &d, AVLNode *& t)
{
  for (auto p = d.begin(); p != d.end(); p++)
  {
    Insert(*p, t);
  }
}
template<typename Comparable>
void AVLTree<Comparable>::Remove(const Comparable & x, AVLNode *& t)
{
  if (t == nullptr) //没找到相应的项什么都不做
    return;
  if (x < t->element)
    Remove(x, t->left);
  else if (x > t->element)
    Remove(x, t->right);
  else if (t->left != nullptr && t->right != nullptr)//找到了 但是有两个儿子
  {//取右子树的最小元素替代 或者左子树的最大元素,好处是右子树的最小元素一定在右子树的最左边,左子树的最大元素一定在左子树的最右边
    t->element = findMin(t->right)->element;//在右子树中找到最小的元素填充删除结点
    Remove(t->element, t->right);//在删除节点的右子树中删除最小元素.
  }
  else //有一个儿子 或者没有
  {
    AVLNode * oldNode = t;
    t = (t->left != nullptr) ? t->left : t->right; //如果有儿子,就让儿子接上,如果没有那t就设置为nullptr
    delete oldNode;
  }
  balance(t);
}
template<typename Comparable>
typename AVLTree<Comparable>::AVLNode *
AVLTree<Comparable>::findMin(AVLNode * t) const
{
  //递归版本
  //if (t == nullptr)  
  //  return nullptr;
  //if (t->left == nullptr)
  //  return t;
  //return findMin(t->left);
  //非递归版本
  if (t != nullptr)
    while (t->left != nullptr)
      t = t->right;
  return t;
}
template<typename Comparable>
typename AVLTree<Comparable>::AVLNode *
AVLTree<Comparable>::findMax(AVLNode * t)const
{
  //递归版本
  /*if (t == nullptr)
    return;
  if (t->right == nullptr)
    return t;
  return findMax(t->right);*/
  if (t != nullptr)
    while (t->right != nullptr)
      t = t->right;
  return t;
}
template<typename Comparable>
bool AVLTree<Comparable>::contains(const Comparable & x, AVLNode * t) const
{
  //递归版本
  /*if (t == nullptr)
    return false;
  else if (x < t->element)
    return contains(x, t->left);
  else if (x > t->element)
    return contains(x, t->right);
  else
    retu true;*/
    //非递归版本
  while (t != nullptr)
  {
    if (x < t->element)
      t = t->left;
    else if (x > t->element)
      t = t->right;
    else
      return true;
  }
  return false;
}
template<typename Comparable>
void AVLTree<Comparable>::makeEmpty(AVLNode *& t)
{
  if (t != nullptr)
  {
    makeEmpty(t->left);
    makeEmpty(t->right);
    delete t;
  }
  t = nullptr;
}
template<typename Comparable>
void AVLTree<Comparable>::PrintTree(AVLNode * t) const
{
  //递归先序遍历
  if (t != nullptr)
  {
    std::cout << t->element << " "; //先序遍历
    PrintTree(t->left);
    PrintTree(t->right);
  }
  //非递归的先序遍历, 使用栈
  //AVLNode * temp = t;
  //stack<AVLNode*>s;
  //while (temp || !s.empty())
  //{
  //  while (temp) //一直向左将沿途结点压入栈
  //  {
  //    s.push(temp);
  //    temp = temp->left;
  //  }
  //  if (!s.empty())
  //  {
  //    temp = s.top();
  //    s.pop();
  //    std::cout << temp->element << " "; //先序遍历
  //    temp = temp->right;
  //  }
  //}
  //层序遍历,使用队列
  //AVLNode * temp;
  //queue<AVLNode*>q;
  //if (t == nullptr)
  //  return;
  //q.push(t);
  //while (!q.empty())
  //{
  //  temp = q.front();
  //  q.pop();
  //  std::cout << temp->element << " ";
  //  if (temp->left)
  //    q.push(temp->left);
  //  if (temp->right)
  //    q.push(temp->right);
  //}
}
template<typename Comparable>
void AVLTree<Comparable>::rotateWithLeftChild(AVLNode *& k2)//左旋
{
  AVLNode *k1 = k2->left;
  k2->left = k1->right;
  k1->right = k2;
  k2->height = Max(height(k2->left), height(k2->right)) + 1;
  k1->height = Max(height(k1->left), k2->height) + 1;
  k2 = k1;//把所有的设置都变为改变后的设置
}
template<typename Comparable>
void AVLTree<Comparable>::rotateWithRightChild(AVLNode *& k2)//右旋
{
  AVLNode *k1 = k2->right;
  k2->right = k1->left;
  k1->left = k2;
  k2->height = Max(height(k2->right), height(k2->left)) + 1;
  k1->height = Max(height(k1->right), k2->height) + 1;
  k2 = k1;
}
template<typename Comparable>
void AVLTree<Comparable>::doubleWithLeftChild(AVLNode *& k3)//左右旋转
{
  rotateWithRightChild(k3->left);
  rotateWithLeftChild(k3);
}
template<typename Comparable>
void AVLTree<Comparable>::doubleWithRightChild(AVLNode *& k3)//右左旋转
{
  rotateWithLeftChild(k3->right);
  rotateWithRightChild(k3);
}
template<typename Comparable>
void AVLTree<Comparable>::balance(AVLNode *& t)
{
  if (t == nullptr)
  {
    return;
  }
  if (height(t->left) - height(t->right) > ALLOWED_IMBLANCE)
    if (height(t->left->left) >= height(t->left->right))
      rotateWithLeftChild(t);
    else
      doubleWithLeftChild(t);
  else if(height(t->right) - height(t->left) > ALLOWED_IMBLANCE)
    if (height(t->right->right) >= height(t->right->left))
      rotateWithRightChild(t);
    else
      doubleWithRightChild(t);
  t->height = max(height(t->left), height(t->right)) + 1;
}


相关文章
|
8天前
|
算法 Java
算法系列之数据结构-Huffman树
Huffman树(哈夫曼树)又称最优二叉树,是一种带权路径长度最短的二叉树,常用于信息传输、数据压缩等方面。它的构造基于字符出现的频率,通过将频率较低的字符组合在一起,最终形成一棵树。在Huffman树中,每个叶节点代表一个字符,而每个字符的编码则是从根节点到叶节点的路径所对应的二进制序列。
33 3
 算法系列之数据结构-Huffman树
|
3天前
|
存储 自然语言处理 数据库
【数据结构进阶】AVL树深度剖析 + 实现(附源码)
在深入探讨了AVL树的原理和实现后,我们不难发现,这种数据结构不仅优雅地解决了传统二叉搜索树可能面临的性能退化问题,还通过其独特的平衡机制,确保了在任何情况下都能提供稳定且高效的查找、插入和删除操作。
40 19
|
4月前
|
算法
数据结构之博弈树搜索(深度优先搜索)
本文介绍了使用深度优先搜索(DFS)算法在二叉树中执行遍历及构建链表的过程。首先定义了二叉树节点`TreeNode`和链表节点`ListNode`的结构体。通过递归函数`dfs`实现了二叉树的深度优先遍历,按预序(根、左、右)输出节点值。接着,通过`buildLinkedList`函数根据DFS遍历的顺序构建了一个单链表,展示了如何将树结构转换为线性结构。最后,讨论了此算法的优点,如实现简单和内存效率高,同时也指出了潜在的内存管理问题,并分析了算法的时间复杂度。
86 0
|
2月前
|
存储 C++
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
【数据结构——树】哈夫曼树(头歌实践教学平台习题)【合集】目录 任务描述 相关知识 测试说明 我的通关代码: 测试结果:任务描述 本关任务:编写一个程序构建哈夫曼树和生成哈夫曼编码。 相关知识 为了完成本关任务,你需要掌握: 1.如何构建哈夫曼树, 2.如何生成哈夫曼编码。 测试说明 平台会对你编写的代码进行测试: 测试输入: 1192677541518462450242195190181174157138124123 (用户分别输入所列单词的频度) 预
72 14
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
|
2月前
|
Java C++
【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
61 12
|
2月前
|
C++
【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
本文档介绍了如何根据二叉树的括号表示串创建二叉树,并计算其结点个数、叶子结点个数、某结点的层次和二叉树的宽度。主要内容包括: 1. **定义二叉树节点结构体**:定义了包含节点值、左子节点指针和右子节点指针的结构体。 2. **实现构建二叉树的函数**:通过解析括号表示串,递归地构建二叉树的各个节点及其子树。 3. **使用示例**:展示了如何调用 `buildTree` 函数构建二叉树并进行简单验证。 4. **计算二叉树属性**: - 计算二叉树节点个数。 - 计算二叉树叶子节点个数。 - 计算某节点的层次。 - 计算二叉树的宽度。 最后,提供了测试说明及通关代
60 10
|
2月前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
61 2
|
4月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
110 5
|
4月前
|
算法
数据结构之文件系统模拟(树数据结构)
本文介绍了文件系统模拟及其核心概念,包括树状数据结构、节点结构、文件系统类和相关操作。通过构建虚拟环境,模拟文件的创建、删除、移动、搜索等操作,展示了文件系统的基本功能和性能。代码示例演示了这些操作的具体实现,包括文件和目录的创建、移动和删除。文章还讨论了该算法的优势和局限性,如灵活性高但节点移除效率低等问题。
100 0
|
6天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于生物地理算法的MLP多层感知机优化matlab仿真
本程序基于生物地理算法(BBO)优化MLP多层感知机,通过MATLAB2022A实现随机数据点的趋势预测,并输出优化收敛曲线。BBO模拟物种在地理空间上的迁移、竞争与适应过程,以优化MLP的权重和偏置参数,提升预测性能。完整程序无水印,适用于机器学习和数据预测任务。

推荐镜像

更多