关于平衡二叉树的传说听多了,“某某大厂笔试手撕平衡二叉树实现代码······”等,好像这是一个非常高深的难题似的,现在学习数据结构的时候遇到了,认真拿来看了看,发现不过如此。任何一个算法,理清楚它为什么这么做,然后根据代码看看它是怎么做到的,那也就不难了。
关于平衡二叉树的讲解网上非常多,各位大佬讲解鞭辟入里,这里推荐一个:https://blog.csdn.net/u014165620/article/details/82492099
讲的虽然多,但是正儿八经用C#代码完整写出来的却很少,这里我结合上述的代码和我自己的思考,分享我的C#AVL树代码:
using System;
namespace AVL树
{
class Node
{
public int val;
public Node left;
public Node right;
//注意这个hight默认初始值为0
public int hight;
public Node(int item)
{
val = item;
}
}
class AVLtree
{
//AVL树的初始根节点,这个并不想BST那样一直不变
//AVL树的根节点是会发生变化的
public Node rootnode;
//返回当前这个node节点的高度,如果为空是-1
public int GetHight(Node node)
{
return node == null ? -1 : node.hight;
}
//在当前root节点中插入值为item的节点
public Node Insert(int item ,Node root)
{
if(root == null)
{
return new Node(item);
}
if(item < root.val)
{
//递归进行,递归中会进行子树的初步链接和当前root节点高度的计算
root.left = Insert(item, root.left);
}
else if(item > root.val)
{
//递归进行,递归中会进行子树的初步链接和当前root节点高度的计算
root.right = Insert(item, root.right);
}
else
{
Console.WriteLine("值:" + item + "已经存在,禁止重复插入");
}
//每个节点都会经历这个操作,除了最开始的根节点
//一方面是恢复平衡,另一方面是获取当前节点的高度
return Balance(root);
}
public Node Balance(Node root)
{
if (root == null) return null;
if(GetHight(root.left) - GetHight(root.right) > 1)
{
if(GetHight(root.left.left) >= GetHight(root.left.right))
{
//对应结构如下
/3
2
///1
root = rotateRight(root);
}
else
{
//对应结构
///5
//3
///4
root = rotateLeftandRight(root);
}
}
else if(GetHight(root.right) - GetHight(root.left) > 1)
{
if (GetHight(root.right.right) >= GetHight(root.right.left))
{
//对应结构如下
///1
2
/3
root = rotateLeft(root);
}
else
{
//对应结构
///5
4
///3
root = rotateRightandLeft(root);
}
}
else {; }
//这个加1很关键,在每次插入元素递归时,可以计算当前节点的hight值
root.hight = Math.Max(GetHight(root.left), GetHight(root.right)) + 1;
return root;
}
public Node rotateLeft(Node root)
{
Node node = root.right;
root.right = node.left;
node.left = root;
root.hight = Math.Max(GetHight(root.left), GetHight(root.right))+1;
node.hight = Math.Max(GetHight(node.left), GetHight(node.right))+1;
return node;
}
public Node rotateRight(Node root)
{
Node node = root.left;
root.left = node.right;
node.right = root;
root.hight = Math.Max(GetHight(root.left), GetHight(root.right))+1;
node.hight = Math.Max(GetHight(node.left), GetHight(node.right))+1;
return node;
}
public Node rotateRightandLeft(Node root)
{
root.right = rotateRight(root.right);
return rotateLeft(root);
}
public Node rotateLeftandRight(Node root)
{
root.left = rotateLeft(root.left);
return rotateRight(root);
}
}
class Program
{
static void Main(string[] args)
{
AVLtree avl = new AVLtree();
for (int i = 0; i < 5; i++)
{
//AVL树不易理解,但是可以在此处设置单点调试
//观察每个节点的插入、高度计算、平衡调整等操作
avl.rootnode = avl.Insert(i,avl.rootnode);
}
Console.WriteLine(avl.GetHight(avl.rootnode));
}//在此处设置单点调试,看每个节点的关系
}
}
AVL树的过程确实不太容易理解,尤其是针对LR和RL型树,但是大家可以通过VS的单点调试功能,观察执行过程中每个节点的变化
有问题请留言哦~