C#实现平衡查找树

C# 实现平衡查找树的完整攻略如下:

什么是平衡查找树

平衡查找树也称 AVL 树,是一种非常高效的数据结构,用于存储和查找有序的数据,平衡查找树的特点是保证了树的高度始终是 O(log n),这样可以在 O(log n) 时间内查找任何一个元素。平衡查找树常用于数据库索引、文件系统和网络路由器中等需要高效查找的场景。

平衡查找树的实现

平衡查找树的实现需要满足两个条件:

  • 每个节点的左右子树高度差不大于 1
  • 每个节点存储的关键字大于它左子树的所有关键字,小于它右子树的所有关键字。

为了保证平衡查找树的高度始终是 O(log n),我们需要对插入和删除操作进行维护,具体的实现过程包括:

插入操作

  1. 先按照二叉查找树的方式将新节点插入到树中。
  2. 插入后对节点的父节点进行旋转操作,使节点的左右子树高度差不大于 1,旋转的方式有四种,单旋转(LL 和 RR)和双旋转(LR 和 RL),具体实现如下:

左旋转(LL)

当某个节点的右子树高度比左子树高度大于 1 时,我们需要进行左旋转(也称单旋转),如下图所示:

     p                                       pl  
    / \                                     /   \  
   pl  Pr                ==>              ll     p  
  / \                                     / \   / \  
ll  lr                                  p1 p2 lr pr 
 / \
p1 p2

右旋转(RR)

当某个节点的左子树高度比右子树高度大于 1 时,我们需要进行右旋转(也称单旋转),如下图所示:

       p                                            pr  
      / \                                          /   \  
     Pl  Pr                  ==>                 p     rr  
         / \                                     / \   / \  
        rl rr                                  pl pr1 pr2 
       / \
      pr1 pr2

双旋转(LR)

当某个节点的右子树高度比左子树高度小于 -1,同时右子树的左子树高度比右子树的右子树高度大于 1 时,我们需要进行双旋转(LR),具体的操作是先对右子节点进行右旋转,再对父节点进行左旋转,如下图所示:

       p                                        pl  
      / \                                      /    \  
    Pl  Pr               ==>                 pr      p  
    / \                                     / \     / \  
   bl  pr                          ==>     bl  bll bll prr  
      / \  
    bll  prr 

双旋转(RL)

当某个节点的左子树高度比右子树高度小于 -1,同时左子树的右子树高度比左子树的左子树高度大于 1 时,我们需要进行双旋转(RL),具体的操作是先对左子节点进行左旋转,再对父节点进行右旋转,如下图所示:

      p                                            pr  
     / \                                          /   \  
   Pl  Pr               ==>                     p     pl  
   / \                                           / \   / \  
 bl  pr                                        bl pr1 pl1 pr2  
     / \  
   pl1  pr1

删除操作

  1. 先按照二叉查找树的方式将节点从树中删除。
  2. 删除后对节点的父节点进行旋转操作,同样保证节点的左右子树高度差不大于 1。

示例说明

以下是一个简单的示例,展示如何使用 C# 实现平衡查找树:

// 定义平衡查找树的节点
public class AVLNode<T>
{
    public T Data;
    public AVLNode<T> Left;
    public AVLNode<T> Right;
    public int Height;
}

// 定义平衡查找树
public class AVLTree<T>
{
    private AVLNode<T> _root;

    // 插入节点
    public void Insert(T data)
    {
        _root = Insert(_root, data);
    }

    // 递归地插入节点
    private AVLNode<T> Insert(AVLNode<T> node, T data)
    {
        if (node == null)
        {
            return new AVLNode<T>() { Data = data, Height = 1 };
        }

        if (Comparer<T>.Default.Compare(data, node.Data) < 0)
        {
            node.Left = Insert(node.Left, data);
        }
        else
        {
            node.Right = Insert(node.Right, data);
        }

        node.Height = Math.Max(GetHeight(node.Left), GetHeight(node.Right)) + 1;

        int balance = GetBalance(node);

        // 左旋转
        if (balance > 1 && Comparer<T>.Default.Compare(data, node.Left.Data) < 0)
        {
            return RotateRight(node);
        }

        // 右旋转
        if (balance < -1 && Comparer<T>.Default.Compare(data, node.Right.Data) > 0)
        {
            return RotateLeft(node);
        }

        // LR 双旋转
        if (balance > 1 && Comparer<T>.Default.Compare(data, node.Left.Data) > 0)
        {
            node.Left = RotateLeft(node.Left);
            return RotateRight(node);
        }

        // RL 双旋转
        if (balance < -1 && Comparer<T>.Default.Compare(data, node.Right.Data) < 0)
        {
            node.Right = RotateRight(node.Right);
            return RotateLeft(node);
        }

        return node;
    }

    // 删除节点
    public void Delete(T data)
    {
        _root = Delete(_root, data);
    }

    // 递归地删除节点
    private AVLNode<T> Delete(AVLNode<T> node, T data)
    {
        if (node == null)
        {
            return null;
        }

        if (Comparer<T>.Default.Compare(data, node.Data) < 0)
        {
            node.Left = Delete(node.Left, data);
        }
        else if (Comparer<T>.Default.Compare(data, node.Data) > 0)
        {
            node.Right = Delete(node.Right, data);
        }
        else
        {
            if (node.Left == null)
            {
                return node.Right;
            }
            else if (node.Right == null)
            {
                return node.Left;
            }

            AVLNode<T> temp = GetMinNode(node.Right);
            node.Data = temp.Data;
            node.Right = Delete(node.Right, temp.Data);
        }

        node.Height = Math.Max(GetHeight(node.Left), GetHeight(node.Right)) + 1;

        int balance = GetBalance(node);

        // 左旋转
        if (balance > 1 && GetBalance(node.Left) >= 0)
        {
            return RotateRight(node);
        }

        // 右旋转
        if (balance < -1 && GetBalance(node.Right) <= 0)
        {
            return RotateLeft(node);
        }

        // LR 双旋转
        if (balance > 1 && GetBalance(node.Left) < 0)
        {
            node.Left = RotateLeft(node.Left);
            return RotateRight(node);
        }

        // RL 双旋转
        if (balance < -1 && GetBalance(node.Right) > 0)
        {
            node.Right = RotateRight(node.Right);
            return RotateLeft(node);
        }

        return node;
    }

    // 节点右旋转
    private AVLNode<T> RotateRight(AVLNode<T> node)
    {
        AVLNode<T> left = node.Left;
        AVLNode<T> right = left.Right;

        left.Right = node;
        node.Left = right;

        node.Height = Math.Max(GetHeight(node.Left), GetHeight(node.Right)) + 1;
        left.Height = Math.Max(GetHeight(left.Left), GetHeight(left.Right)) + 1;

        return left;
    }

    // 节点左旋转
    private AVLNode<T> RotateLeft(AVLNode<T> node)
    {
        AVLNode<T> right = node.Right;
        AVLNode<T> left = right.Left;

        right.Left = node;
        node.Right = left;

        node.Height = Math.Max(GetHeight(node.Left), GetHeight(node.Right)) + 1;
        right.Height = Math.Max(GetHeight(right.Left), GetHeight(right.Right)) + 1;

        return right;
    }

    // 获取节点的高度
    private int GetHeight(AVLNode<T> node)
    {
        return node == null ? 0 : node.Height;
    }

    // 获取节点的平衡因子
    private int GetBalance(AVLNode<T> node)
    {
        return node == null ? 0 : GetHeight(node.Left) - GetHeight(node.Right);
    }

    // 获取以某个节点为根节点的最小节点
    private AVLNode<T> GetMinNode(AVLNode<T> node)
    {
        while (node.Left != null)
        {
            node = node.Left;
        }

        return node;
    }
}

以上代码展示了一个简单的平衡查找树的实现,包括插入和删除操作。我们可以通过以下代码测试平衡查找树的效果:

AVLTree<int> tree = new AVLTree<int>();
Random rnd = new Random();

for (int i = 0; i < 10; i++)
{
    int n = rnd.Next(1, 100);
    Console.WriteLine("Insert: " + n);
    tree.Insert(n);
}

Console.WriteLine("===== InorderTraversal Result =====");
tree.InorderTraversal(tree.Root);
Console.WriteLine("===================================");

for (int i = 0; i < 5; i++)
{
    int n = rnd.Next(1, 100);
    Console.WriteLine("Delete: " + n);
    tree.Delete(n);
}

Console.WriteLine("===== InorderTraversal Result =====");
tree.InorderTraversal(tree.Root);
Console.WriteLine("===================================");

以上代码随机生成了 10 个数插入平衡查找树中,然后随机删除其中 5 个数,并输出中序遍历的结果。我们可以通过不断运行这个测试代码,观察平衡查找树的高度是否一直保持在 O(log n),可以看到平衡查找树的高度始终保持在 O(log n) 左右,证明了平衡查找树的实现是正确的。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#实现平衡查找树 - Python技术站

(0)
上一篇 2023年6月8日
下一篇 2023年6月8日

相关文章

  • c#压缩字符串的方法

    让我来详细讲解一下c#压缩字符串的方法的完整攻略。 为什么需要压缩字符串? 在实际开发中,传输数据是一个常见的需求。然而,如果数据过大,传输所需的时间和网络带宽都会增加,这对网站的性能会产生不良的影响。为了解决这个问题,压缩字符串是一个好的选择。压缩后的字符串文件体积会变小,传输时所需的时间和带宽也会变小。 c#字符串压缩的方法 1. 使用GZipStrea…

    C# 2023年5月31日
    00
  • 学习TraceLogging事件,使用ETW记录,并使用WPA捕获和分析跟踪

    优化响应行为的交互 下载WINDOWS评估和部署工具包 (Windows ADK) 保持默认安装 驱动延迟优化的基本步骤包括: 定义方案并添加 TraceLogging 事件。TraceLogging 是用于日志记录事件的系统,无需清单即可解码,TraceLogging基于windows事件跟踪(ETW),并提供检测代码的简化办法。C#可选的有.NET Ev…

    C# 2023年4月30日
    00
  • C#命令模式(Command Pattern)实例教程

    C#命令模式(Command Pattern)是一种行为型设计模式,它允许将操作请求封装为独立的对象,从而将请求的发起者和接收者解耦。 实现过程 定义命令接口 首先需要定义一个命令接口,它至少应该包含一个执行方法(Execute)和一个撤销方法(Undo): public interface ICommand { void Execute(); void U…

    C# 2023年6月7日
    00
  • C#6.0中你可能不知道的新特性总结

    C#6.0是微软在2015年发布的新版本,增加了不少新特性。本文将对C#6.0中一些可能被忽略的新特性进行总结和分享。 1. 自动属性初始值设定 在C#6.0引入了自动属性初始值设定,开发者可以为属性提供一个初始值,而不必在构造函数中进行设置。这种方式可以更加方便快捷地编写C#代码。 示例: public class Person { public stri…

    C# 2023年5月31日
    00
  • asp.net Split分割字符串的方法

    当使用ASP.NET进行开发时,分割字符串是一项非常常见的任务。ASP.NET中的Split()方法是一种简单有效的将字符串分成单独纯文本段的方法。 Split()方法的基本用法 Split()方法可以用于按照指定的分隔符将一个字符串分割成多个子串。其基本用法如下所示: string str = "apple, banana, cherry, da…

    C# 2023年6月3日
    00
  • 浅析C#中的AsnycLocal与ThreadLocal

    浅析C#中的AsyncLocal与ThreadLocal 在C#中,当多个线程同时访问同一个变量时,需要使用线程安全的方式保护变量,避免数据竞争。AsyncLocal和ThreadLocal就是两种常用的线程安全技术。 引言 AsyncLocal AsyncLocal是.NET Framework 4.6中引入的一种用于在异步代码中存储和检索数据的新机制。它…

    C# 2023年5月15日
    00
  • .NET Core配置连接字符串和获取数据库上下文实例

    关于如何在.NET Core中配置连接字符串和获取数据库上下文实例,以下是详细攻略: 步骤一:在appsettings.json文件中配置数据库连接字符串 在.NET Core应用程序的根目录下有一个appsettings.json文件,我们可以在其中配置数据库连接字符串。以下是配置示例: { "ConnectionStrings": {…

    C# 2023年6月3日
    00
  • .net任务调度框架Hangfire简介

    .NET任务调度框架Hangfire简介 Hangfire是一个.NET任务调度框架,它可以帮助我们在.NET应用程序中轻松地执行后台任务。Hangfire提供了一个简单的API,可以让我们创建和管理后台任务,例如发送电子邮件、生成报告、处理队列等。Hangfire还提供了一个可视化仪表板,可以让我们轻松地监视和管理后台任务。 安装Hangfire 我们可以…

    C# 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部