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# 多线程记录

    ​  开发中经常遇到不同的业务访问同一个数据源,而每一个业务的执行流就是一个线程,此时线程一多就会产生多线程最容易遇到的问题——并发。 什么是并发?         举个很经典的例子:程序中我们经常要操作一些对象,尤其是内存中的数据                    例如当前判断进入条件已经判断newModel不为空,sleep(10)称为比较耗时的运算…

    C# 2023年4月24日
    00
  • 使用.NET升级助手将.NET Framework项目升级为.NET 6

    使用.NET升级助手将.NET Framework项目升级为.NET 6 本攻略将介绍如何使用.NET升级助手将.NET Framework项目升级为.NET 6。以下是完整的攻略步骤。 步骤 步骤1:安装.NET升级助手 首先,需要安装.NET升级助手。可以使用以下命令在命令行中安装.NET升级助手: dotnet tool install -g upgr…

    C# 2023年5月17日
    00
  • C#中可空类型的使用

    当我们需要在C#中表示一个可以为null的值时,可空类型(Nullable Types)是非常有用的,它允许我们将值类型(Value Types)赋予null的能力。 定义可空类型 C#中的可空类型是由该类型名称和一个问号(?)组成的,例如: int? num = null; double? price = 3.99; 以上代码中,int?类型表示一个可以为…

    C# 2023年6月1日
    00
  • C#使用Process类调用外部exe程序

    一、介绍 在使用C#进行编程的过程中,有时需要使用外部程序来进行特定的操作。在这种情况下,可以使用Process类进行操作。Process类是C#中用于启动外部进程的类,它允许我们创建、控制和执行操作系统中的进程,比如启动一个Windows应用程序或者调用另一个可执行文件。 二、基本用法 使用Process类调用外部exe程序的基本流程如下: 首先创建一个P…

    C# 2023年6月7日
    00
  • 探讨jQuery的ajax使用场景(c#)

    探讨 jQuery 的 ajax 使用场景(c#) 什么是 ajax ajax 是 Asynchronous JavaScript and XML 的缩写,也就是异步的 JavaScript 和 XML。它是一种无需刷新整个页面就可以与服务器进行数据交互的技术。 jQuery 中的 ajax jQuery 提供了一些方便的方式来实现 ajax。通过 jQue…

    C# 2023年5月31日
    00
  • 解析如何正确使用SqlConnection的实现方法

    SqlConnection是 .NET 中提供的一个用于访问 SQL Server 的数据提供程序,可以用于打开数据库连接、执行 SQL语句、处理结果等操作。正确使用 SqlConnection 是编写高效、可靠的 ADO.NET 应用程序的必要条件。本文将详细介绍在 C# 中正确使用 SqlConnection 的方法。 创建 SqlConnection …

    C# 2023年5月31日
    00
  • C# 实现在控制台上换行输出与不换行输出

    C# 实现在控制台上换行输出与不换行输出 在C#中,我们可以使用Console.WriteLine()方法以及Console.Write()方法实现在控制台上换行输出与不换行输出。 换行输出 使用Console.WriteLine()方法可以实现在控制台上换行输出。以下是该方法的语法: Console.WriteLine(); 当我们在调用Console.W…

    C# 2023年6月7日
    00
  • C# File.ReadAllText(string path):读取指定文件的所有文本内容

    C#的File.ReadAllText(string path)方法用于读取指定文件的所有文本内容,并以字符串形式返回。该方法适用于读取文本文件中的数据,如果尝试读取非文本文件(如二进制图像),则会导致方法执行失败。 方法参数 File.ReadAllText() 方法需要传入表示文件路径的字符串类型参数,指定要读取的文件。 返回值 File.ReadAll…

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