泛型平衡二叉树(C#)

概念

平衡二叉树,简称 AVL

实现平衡二叉树,需要先了解二叉搜索树

二叉搜索树(BST,Binary Search Tree),也称二叉排序树或二叉查找树。
二叉搜索树:一棵二叉树,可以为空;如果不为空,满足以下性质:

  1. 非空左子树的所有键值小于其根结点的键值。
  2. 非空右子树的所有键值大于其根结点的键值。
  3. 左、右子树都是二叉搜索树

二叉搜索树的缺点:在数据不合理的情况下,二叉搜索树会向 链条状 退化,因此查找效率就会从O(log n)变为O(n)

针对二叉搜索树的退化现象,将每个结点左右子树的 高度差(绝对值) 控制在 1 以内,即为平衡二叉树

        左右子树的高度差,称为该结点的平衡因子(balance)

平衡二叉树的定义:
1、平衡二叉树 必须是 二叉搜索树
2、平衡二叉树内每个结点左右子树的 高度差(平衡因子) ∈ [-1,1]

使用C#实现平衡二叉树

实现泛型平衡二叉树的思路基于泛型二叉搜索树

如果没有泛型二叉搜索树的手搓经验,可以先看这篇文章泛型二叉搜索树(C#)icon-default.png?t=N7T8https://blog.csdn.net/qq_51613678/article/details/134753106

泛型实现思路:将结点的数据类型定义为 T (泛型),满足“字符串、数字、数组” 等数据类型

解决数据比较问题:

        在插入值时,需要将插入值与当前结点的值进行比较,如果数据类型为 T ,值之间的比较方法就需要由创建二叉搜索树的类,自定义回调方法

        使用 deledage (委托) 实现回调

采用非递归实现所有功能

二叉树的结构

public class TreeNode<T>
{
    public int height;                  // 树高
    public T content;                   // 内容
    public TreeNode<T> left;            // 左子树
    public TreeNode<T> right;           // 右子树
    public TreeNode<T> parent;          // 父节点
}

height为树高,存储该结点的高度值,并提供给父结点计算平衡因子

自定义比较函数的结构

使用 delegate(委托) 制作 比较函数

由于平衡二叉树中需要判断两个结点内的值 ①是否相等 ②谁大谁小

因此比较函数分为两个制作:

1、判断两个值是否相等

2、比较两个值的大小

定义结构如下:

public delegate bool CompareEqual(T a, T b);   // 判断相等, false为 a!=b ,true为 a=b
public delegate bool Compare(T a, T b);        // 判断大小, false为 a<b ,true为 a>b

泛型二叉树控制器

_treeNode: 二叉树的根节点

_compareEqual: 判断两个值是否相等

_compare: 比较两个值的大小

public class TreeControllNew<T>
{
    public delegate bool CompareEqual(T a, T b); // 判断相等, false为 a!=b ,true为 a=b
    public delegate bool Compare(T a, T b); // 判断大小, false为 a<b ,true为 a>b

    private TreeNode<T> _treeNode;
    private CompareEqual _compareEqual;
    private Compare _compare;

    public TreeControllNew(T[] contents, CompareEqual compareEqual, Compare compare)
    {
        _compareEqual = compareEqual;
        _compare = compare;
        for (int i = 0; i < contents.Length; i++)
        {
            Insert(contents[i]);
        }
    }

    public TreeControllNew(CompareEqual compareEqual, Compare compare)
    {
        _compareEqual = compareEqual;
        _compare = compare;
    }
}

创建存储 int 类型的平衡二叉树
// 构造数据
int[] nums = new[] {15, 10, 19, 8, 13, 16, 28, 5, 9, 12, 14, 20, 30, 25};
TreeControll<int> treeControll = new TreeControll<int>(nums, 
    delegate(int i, int i1)
    {
        return i == i1;
    },
    delegate(int i, int i1)
    {
        return i > i1;
    });

以上:基础建设已完成

维持平衡的概念

已知二叉搜索树满足一个基本要求:

        1、左子节点一定小于自身

        2、右子节点一定大于自身

平衡二叉树自然也满足该条件,所以维持平衡只需要在 插入&删除 完成后,从该结点向上回溯,判断每个父结点的平衡因子是否满足平衡要求:

        不满足则进行 旋转

结点旋转分为两种:左旋右旋

左旋:

        1、当前结点的右子树会变成新树的根结点
        2、当前结点会作为新树根结点的左子树
         3、如果新树原先存在左子树,那么该左子树将作为旧根结点的右子树

右旋:

        1、当前结点的左子树会变成新树的根结点
         2、当前结点会作为新树根结点的右子树
        3、如果新树原先存在右子树,那么该左子树将作为旧根结点的左子树

单左旋转函数

根据上述概念,写出 单左旋转函数,负责将传入的结点向左旋转

private void leftRoate(TreeNode<T> treeNode)
{
    // 1、当前结点的右子树会变成新树的根结点
    // 2、当前结点会作为新树根结点的左子树
    // 3、如果新树原先存在左子树,那么该左子树将作为旧根结点的右子树
    TreeNode<T> newNode = treeNode.right;
    TreeNode<T> newNodeLeft = newNode.left;

    newNode.left = treeNode;
    newNode.parent = treeNode.parent;
    treeNode.parent = newNode;
    treeNode.right = newNodeLeft;
    if (newNodeLeft != null)
        newNodeLeft.parent = treeNode;

    if (newNode.parent != null)
    {
        if (_compare(newNode.content, newNode.parent.content))
            newNode.parent.right = newNode;
        else
            newNode.parent.left = newNode;
    }
            
    treeNode.height = 1 + Math.Max(getNodeHeight(treeNode.left), getNodeHeight(treeNode.right));
    newNode.height = 1 + Math.Max(getNodeHeight(newNode.left), getNodeHeight(newNode.right));
    if (_compareEqual(treeNode.content, _treeNode.content))
    {
        _treeNode = newNode;
    }
}

单右旋转函数

写出 单右旋转函数,负责将传入的结点向右旋转

private void rightRoate(TreeNode<T> treeNode)
{
    // 1、当前结点的左子树会变成新树的根结点
    // 2、当前结点会作为新树根结点的右子树
    // 3、如果新树原先存在右子树,那么该左子树将作为旧根结点的左子树
    TreeNode<T> newNode = treeNode.left;
    TreeNode<T> newNodeRight = newNode.right;

    newNode.right = treeNode;
    newNode.parent = treeNode.parent;
    treeNode.parent = newNode;
    treeNode.left = newNodeRight;
    if (newNodeRight != null)
        newNodeRight.parent = treeNode;
            
    if (newNode.parent != null)
    {
        if (_compare(newNode.content, newNode.parent.content))
            newNode.parent.right = newNode;
        else
            newNode.parent.left = newNode;
    }

    treeNode.height = 1 + Math.Max(getNodeHeight(treeNode.left), getNodeHeight(treeNode.right));
    newNode.height = 1 + Math.Max(getNodeHeight(newNode.left), getNodeHeight(newNode.right));
    if (_compareEqual(treeNode.content, _treeNode.content))
    {
        _treeNode = newNode;
    }
}

写好旋转函数后,再设计 刷新结点平衡状态函数

该函数负责:

        1、更新传入结点的树高

        2、获取该结点的平衡因子,如果不处于平衡状态,将判断该结点需要使用哪种旋转方式,并进行旋转。

刷新结点平衡状态函数
private void refreshNodeBalance(TreeNode<T> node)
{
    // 重新设置结点高度
    node.height = 1 + Math.Max(getNodeHeight(node.left), getNodeHeight(node.right));
    // 判断平衡因子,如果 平衡因子 > 1,则失衡
    int tmpNodeBalance = getNodeBalance(node);
    // LL型平衡旋转  (单右旋转)
    if (tmpNodeBalance > 1 && getNodeBalance(node.left) > 0)
    {
        rightRoate(node);
    }
    // RR型平衡旋转  (单左旋转)
    if (tmpNodeBalance < -1 && getNodeBalance(node.right) < 0)
    {
        leftRoate(node);
    }
    // LR型平衡旋转  (先左后右双旋转)
    if (tmpNodeBalance > 1 && getNodeBalance(node.left) < 0)
    {
        leftRoate(node.left);
        rightRoate(node);
    }
    // RL型平衡旋转  (先右后左双旋转)
    if (tmpNodeBalance < -1 && getNodeBalance(node.right) > 0)
    {
        rightRoate(node.right);
        leftRoate(node);
    }
}

至此,最复杂的旋转就解决了

剩下的则是平衡二叉树的 插入,搜索,删除

插入函数

由于使用了非递归的方式,因此需要设计一个栈(Stack)

在插入 A 结点 时,将其经过的结点压入栈内

完成插入后,将栈内的结点一个个取出,刷新结点的平衡状态:refreshNodeBalance(***)

public void Insert(T content)           // 用非递归实现
{
    if (_treeNode == null)
    {
        _treeNode = new TreeNode<T>();
        _treeNode.height = 1;
        _treeNode.content = content;
        return;
    }

    TreeNode<T> curNode = _treeNode;
    Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();
    stack.Push(_treeNode);
    while (true)
    {
        if (_compareEqual(content, curNode.content))
        {
            // 特殊情况:插入的值在树中存在
            Console.WriteLine("插入失败,该值已存在:" + content);
            return;
        }
        
        if (_compare(content, curNode.content))
        {
            if (curNode.right != null)
            {
                stack.Push(curNode.right);
                curNode = curNode.right;
            }
            else
            {
                TreeNode<T> node = new TreeNode<T>();
                node.content = content;
                node.parent = curNode;
                node.height = 1;
                curNode.right = node;
                break;
            }
        }
        else
        {
            if (curNode.left != null)
            {
                stack.Push(curNode.left);
                curNode = curNode.left;
            }
            else
            {
                TreeNode<T> node = new TreeNode<T>();
                node.content = content;
                node.parent = curNode;
                node.height = 1;
                curNode.left = node;
                break;
            }
        }
    }
    // 更新树高
    // curNode.height = 1 + Math.Max(getNodeHeight(curNode.left), getNodeHeight(curNode.right));
    while (stack.Count > 0)
    {
        refreshNodeBalance(stack.Pop());
    }
}

搜索函数

(1)查找从根结点开始,如果树为空,返回NULL
(2)若搜索树非空,则根结点关键字和X进行比较,并进行不同处理:
  ① 若X小于根结点键值,只需在左子树中继续搜索;
  ② 如果X大于根结点的键值,在右子树中进行继续搜索;
  ③若两者比较结果是相等,搜索完成,返回指向此结点的指针。

public TreeNode<T> Find(T content)             // 用非递归实现
{
    // 目前该功能只负责返回 是否找到
    Console.WriteLine("----------------  查找  ---------------");
    bool isFind = false;
    TreeNode<T> curNode = _treeNode;
    while (curNode != null)
    {
        if (_compareEqual(content, curNode.content))
        {
            Console.WriteLine("已找到节点: " + content);
            Console.WriteLine("树高为: " + curNode.height + "    父节点为: " + (curNode.parent != null ? curNode.parent.content.ToString() : "空"));
            isFind = true;
            break;
        }
        if (_compare(content, curNode.content))
        {
            curNode = curNode.right;
        }
        else
        {
            curNode = curNode.left;
        }
    }

    if (!isFind)
    {
        Console.WriteLine("没有找到节点: " + content);
    }
    Console.WriteLine("----------------查找结束---------------\n");
    return isFind ? curNode : null;
}

删除函数

由于使用非递归的方法完成删除,因此也需要设计一个

将最后删除的结点压入栈中

从该结点开始向上回溯(获取父结点),并刷新这个结点的平衡状态

直到当前结点的父结点 == NULL

public void Remove(T content, bool repleaseLeft = true)           // 用非递归实现
{
    /*
     * 1、删除叶子节点:直接删
     * 2、删除的节点只包含一个孩子节点:将该节点的父节点指向该节点的孩子节点
     * 3、删除的节点包含左右节点:找到该节点左子树中的最大元素 或 右子树中的最小元素, 进行替换
     * 4、从最后被删除的结点,往父结点回溯,刷新每个父节点的高度和平衡因子,并判断是否需要平衡旋转
     */
    
    // 找到该节点
    TreeNode<T> curNode = Find(content);
    if (curNode == null)
    {
        Console.WriteLine("未找到该元素");
        return;
    }
    bool isEnd = false;
    Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();
    while (!isEnd)
    {
        if (curNode.left == null && curNode.right == null)              // 叶子结点
        {
            if (curNode.parent != null)
            {
                if (_compare(curNode.content, curNode.parent.content))
                    curNode.parent.right = null;
                else
                    curNode.parent.left = null;
                stack.Push(curNode.parent);
            }
            curNode = null;
            isEnd = true;
        }
        else if(curNode.left != null && curNode.right != null)          // 存在左右节点
        {
            TreeNode<T> replaceNode;
            if (repleaseLeft)       // 找到左节点最大的节点
            {
                replaceNode = curNode.left;
                while (replaceNode.right != null)
                {
                    replaceNode = replaceNode.right;
                }
            }
            else                    // 找到右节点最小的节点
            {
                replaceNode = curNode.right;
                while (replaceNode.left != null)
                {
                    replaceNode = replaceNode.left;
                }
            }
            curNode.content = replaceNode.content;
            curNode = replaceNode;
        }
        else                                                            // 只存在一个子节点
        {
            TreeNode<T> tmpNode;
            if (curNode.left != null)
                tmpNode = curNode.left;
            else
                tmpNode = curNode.right;
            tmpNode.parent = curNode.parent;
            curNode = null;
            if (_compare(tmpNode.content, tmpNode.parent.content))
                tmpNode.parent.right = tmpNode;
            else
                tmpNode.parent.left = tmpNode;
            stack.Push(tmpNode.parent);
            isEnd = true;
        }
    }

    // 回溯父结点,刷新平衡因子
    while (stack.Count > 0)
    {
        TreeNode<T> node = stack.Pop();
        if (node.parent != null)
        {
            stack.Push(node.parent);
        }
        refreshNodeBalance(node);
    }
}

总结

平衡二叉树的优点:

        可以自动更新自身的平衡状态,确保查找的时间复杂度为O(log n)

缺点也很明显,频繁的调整平衡状态、旋转结点也颇耗性能

因此舍弃部分平衡的红黑树则是更优解,得抽空看起来了。。

全部代码

TreeNode.cs

public class TreeNode<T>
{
    public int height;                  // 树高
    public T content;                   // 内容
    public TreeNode<T> left;            // 左子树
    public TreeNode<T> right;           // 右子树
    public TreeNode<T> parent;          // 父节点
}

TreeControll.cs

public class TreeControllNew<T>
{
    public delegate bool CompareEqual(T a, T b);         // 判断相等, false为 a!=b ,true为 a=b
    public delegate bool Compare(T a, T b);              // 判断大小, false为 a<b ,true为 a>b

    private TreeNode<T> _treeNode;
    private CompareEqual _compareEqual;
    private Compare _compare;
    public TreeControllNew(T[] contents, CompareEqual compareEqual, Compare compare)
    {
        _compareEqual = compareEqual;
        _compare = compare;
        for (int i = 0; i < contents.Length; i++)
        {
            Insert(contents[i]);
        }
    }
    
    public TreeControllNew(CompareEqual compareEqual, Compare compare)
    {
        _compareEqual = compareEqual;
        _compare = compare;
    }

    private int getNodeHeight(TreeNode<T> node)
    {
        return node != null ? node.height : 0;
    }
    
    /// <summary>
    /// 单左旋转
    /// </summary>
    /// <param name="treeNode"></param>
    /// <returns></returns>
    private void leftRoate(TreeNode<T> treeNode)
    {
        // 1、当前结点的右子树会变成新树的根结点
        // 2、当前结点会作为新树根结点的左子树
        // 3、如果新树原先存在左子树,那么该左子树将作为旧根结点的右子树
        TreeNode<T> newNode = treeNode.right;
        TreeNode<T> newNodeLeft = newNode.left;

        newNode.left = treeNode;
        newNode.parent = treeNode.parent;
        treeNode.parent = newNode;
        treeNode.right = newNodeLeft;
        if (newNodeLeft != null)
            newNodeLeft.parent = treeNode;

        if (newNode.parent != null)
        {
            if (_compare(newNode.content, newNode.parent.content))
                newNode.parent.right = newNode;
            else
                newNode.parent.left = newNode;
        }
        
        treeNode.height = 1 + Math.Max(getNodeHeight(treeNode.left), getNodeHeight(treeNode.right));
        newNode.height = 1 + Math.Max(getNodeHeight(newNode.left), getNodeHeight(newNode.right));
        if (_compareEqual(treeNode.content, _treeNode.content))
        {
            _treeNode = newNode;
        }
    }
    
    /// <summary>
    /// 单右旋转
    /// </summary>
    /// <param name="treeNode"></param>
    /// <returns></returns>
    private void rightRoate(TreeNode<T> treeNode)
    {
        // 1、当前结点的左子树会变成新树的根结点
        // 2、当前结点会作为新树根结点的右子树
        // 3、如果新树原先存在右子树,那么该左子树将作为旧根结点的左子树
        TreeNode<T> newNode = treeNode.left;
        TreeNode<T> newNodeRight = newNode.right;

        newNode.right = treeNode;
        newNode.parent = treeNode.parent;
        treeNode.parent = newNode;
        treeNode.left = newNodeRight;
        if (newNodeRight != null)
            newNodeRight.parent = treeNode;
        
        if (newNode.parent != null)
        {
            if (_compare(newNode.content, newNode.parent.content))
                newNode.parent.right = newNode;
            else
                newNode.parent.left = newNode;
        }

        treeNode.height = 1 + Math.Max(getNodeHeight(treeNode.left), getNodeHeight(treeNode.right));
        newNode.height = 1 + Math.Max(getNodeHeight(newNode.left), getNodeHeight(newNode.right));
        if (_compareEqual(treeNode.content, _treeNode.content))
        {
            _treeNode = newNode;
        }
    }

    /// <summary>
    /// 刷新结点平衡状态
    /// </summary>
    /// <param name="node"></param>
    private void refreshNodeBalance(TreeNode<T> node)
    {
        // 重新设置结点高度
        node.height = 1 + Math.Max(getNodeHeight(node.left), getNodeHeight(node.right));
        // 判断平衡因子,如果 平衡因子 > 1,则失衡
        int tmpNodeBalance = getNodeBalance(node);
        // LL型平衡旋转  (单右旋转)
        if (tmpNodeBalance > 1 && getNodeBalance(node.left) > 0)
        {
            rightRoate(node);
        }
        // RR型平衡旋转  (单左旋转)
        if (tmpNodeBalance < -1 && getNodeBalance(node.right) < 0)
        {
            leftRoate(node);
        }
        // LR型平衡旋转  (先左后右双旋转)
        if (tmpNodeBalance > 1 && getNodeBalance(node.left) < 0)
        {
            leftRoate(node.left);
            rightRoate(node);
        }
        // RL型平衡旋转  (先右后左双旋转)
        if (tmpNodeBalance < -1 && getNodeBalance(node.right) > 0)
        {
            rightRoate(node.right);
            leftRoate(node);
        }
    }

    /// <summary>
    /// 获取当前结点的平衡因子
    /// </summary>
    /// <param name="node"></param>
    /// <returns></returns>
    private int getNodeBalance(TreeNode<T> node)
    {
        return node != null ? getNodeHeight(node.left) - getNodeHeight(node.right) : 0;
    }
    
    /// <summary>
    /// 插入值
    /// </summary>
    /// <param name="content"></param>
    public void Insert(T content)           // 用非递归实现
    {
        if (_treeNode == null)
        {
            _treeNode = new TreeNode<T>();
            _treeNode.height = 1;
            _treeNode.content = content;
            return;
        }

        TreeNode<T> curNode = _treeNode;
        Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();
        stack.Push(_treeNode);
        while (true)
        {
            if (_compareEqual(content, curNode.content))
            {
                // 特殊情况:插入的值在树中存在
                Console.WriteLine("插入失败,该值已存在:" + content);
                return;
            }
            
            if (_compare(content, curNode.content))
            {
                if (curNode.right != null)
                {
                    stack.Push(curNode.right);
                    curNode = curNode.right;
                }
                else
                {
                    TreeNode<T> node = new TreeNode<T>();
                    node.content = content;
                    node.parent = curNode;
                    node.height = 1;
                    curNode.right = node;
                    break;
                }
            }
            else
            {
                if (curNode.left != null)
                {
                    stack.Push(curNode.left);
                    curNode = curNode.left;
                }
                else
                {
                    TreeNode<T> node = new TreeNode<T>();
                    node.content = content;
                    node.parent = curNode;
                    node.height = 1;
                    curNode.left = node;
                    break;
                }
            }
        }
        // 更新树高
        // curNode.height = 1 + Math.Max(getNodeHeight(curNode.left), getNodeHeight(curNode.right));
        while (stack.Count > 0)
        {
            refreshNodeBalance(stack.Pop());
        }
    }

    /// <summary>
    /// 查找值
    /// </summary>
    /// <param name="content"></param>
    /// <returns></returns>
    public TreeNode<T> Find(T content)             // 用非递归实现
    {
        // 目前该功能只负责返回 是否找到
        Console.WriteLine("----------------  查找  ---------------");
        bool isFind = false;
        TreeNode<T> curNode = _treeNode;
        while (curNode != null)
        {
            if (_compareEqual(content, curNode.content))
            {
                Console.WriteLine("已找到节点: " + content);
                Console.WriteLine("树高为: " + curNode.height + "    父节点为: " + (curNode.parent != null ? curNode.parent.content.ToString() : "空"));
                isFind = true;
                break;
            }
            if (_compare(content, curNode.content))
            {
                curNode = curNode.right;
            }
            else
            {
                curNode = curNode.left;
            }
        }

        if (!isFind)
        {
            Console.WriteLine("没有找到节点: " + content);
        }
        Console.WriteLine("----------------查找结束---------------\n");
        return isFind ? curNode : null;
    }

    /// <summary>
    /// 删除值
    /// </summary>
    /// <param name="content"></param>
    /// <param name="repleaseLeft"> 删除值后的替换元素,是否采用左节点内的元素 </param>
    public void Remove(T content, bool repleaseLeft = true)           // 用非递归实现
    {
        /*
         * 1、删除叶子节点:直接删
         * 2、删除的节点只包含一个孩子节点:将该节点的父节点指向该节点的孩子节点
         * 3、删除的节点包含左右节点:找到该节点左子树中的最大元素 或 右子树中的最小元素, 进行替换
         * 4、从最后被删除的结点,往父结点回溯,刷新每个父节点的高度和平衡因子,并判断是否需要平衡旋转
         */
        
        // 找到该节点
        TreeNode<T> curNode = Find(content);
        if (curNode == null)
        {
            Console.WriteLine("未找到该元素");
            return;
        }
        bool isEnd = false;
        Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();
        while (!isEnd)
        {
            if (curNode.left == null && curNode.right == null)              // 叶子结点
            {
                if (curNode.parent != null)
                {
                    if (_compare(curNode.content, curNode.parent.content))
                        curNode.parent.right = null;
                    else
                        curNode.parent.left = null;
                    stack.Push(curNode.parent);
                }
                curNode = null;
                isEnd = true;
            }
            else if(curNode.left != null && curNode.right != null)          // 存在左右节点
            {
                TreeNode<T> replaceNode;
                if (repleaseLeft)       // 找到左节点最大的节点
                {
                    replaceNode = curNode.left;
                    while (replaceNode.right != null)
                    {
                        replaceNode = replaceNode.right;
                    }
                }
                else                    // 找到右节点最小的节点
                {
                    replaceNode = curNode.right;
                    while (replaceNode.left != null)
                    {
                        replaceNode = replaceNode.left;
                    }
                }
                curNode.content = replaceNode.content;
                curNode = replaceNode;
            }
            else                                                            // 只存在一个子节点
            {
                TreeNode<T> tmpNode;
                if (curNode.left != null)
                    tmpNode = curNode.left;
                else
                    tmpNode = curNode.right;
                tmpNode.parent = curNode.parent;
                curNode = null;
                if (_compare(tmpNode.content, tmpNode.parent.content))
                    tmpNode.parent.right = tmpNode;
                else
                    tmpNode.parent.left = tmpNode;
                stack.Push(tmpNode.parent);
                isEnd = true;
            }
        }

        // 回溯父结点,刷新平衡因子
        while (stack.Count > 0)
        {
            TreeNode<T> node = stack.Pop();
            if (node.parent != null)
            {
                stack.Push(node.parent);
            }
            refreshNodeBalance(node);
        }
    }

    /// <summary>
    /// 打印树
    /// </summary>
    public void PrintOut()
    {
        // 随便打印的,树的形状不一定合理
        Console.WriteLine("---------------------- 打印树 ---------------------");
        if (_treeNode == null)
        {
            Console.WriteLine("树为空");
            return;
        }
        Queue<TreeNode<T>> queue = new Queue<TreeNode<T>>();
        queue.Enqueue(_treeNode);
        int curHeight = _treeNode.height;
        while (queue.Count != 0)
        {
            TreeNode<T> node = queue.Dequeue();
            if (curHeight > node.height)
            {
                curHeight = node.height;
                Console.Write("\n");
            }
            Console.Write(node.content + "(" + node.height + ")" + "   ");
            if (node.left != null)
            {
                queue.Enqueue(node.left);
            }
            if (node.right != null)
            {
                queue.Enqueue(node.right);
            }
        }
        Console.WriteLine("\n----------------------打印结束---------------------\n");
    }
}
main函数代码.cs
public class T_Main
{
    // 平衡二叉树 AVL
    /*
     * 定义:
     *      1、平衡二叉树 必须是 二叉搜索树
     *      2、平衡二叉树内每个结点左右子树的 高度差 <= 1
    */

    /// <summary>
    /// 起始函数
    /// </summary>
    public static void Main(string[] args)
    { 
        // 构造数据
        // int[] nums = new[] {15, 10, 19, 8, 13, 16, 28, 5, 9, 12, 14, 20, 30, 25};
        // int[] nums = new[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
        // int[] nums = new[] {11, 10, 9, 8, 7, 6, 5, 4, ;3, 2, 1, 0};
        int[] nums = new[] {5, 3, 15, 1, 10, 18, 19};
            
        // 创建存储 int 类型的二叉搜索树
        TreeControllNew<int> treeControll = new TreeControllNew<int>(nums, 
            delegate(int i, int i1)
            {
                return i == i1;
            },
            delegate(int i, int i1)
            {
                return i > i1;
            });
            
        // 打印树结构
        treeControll.PrintOut();
            
        // 查找
        // treeControll.Find(15);
        // treeControll.Find(25);
        // treeControll.Find(13);
        // treeControll.Find(-1);
            
        // 删除
        treeControll.Remove(1);
        treeControll.PrintOut();
        treeControll.Remove(15);
        treeControll.PrintOut();
    }
}

  • 33
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不伤欣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值