C#数据结构之Tree
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AlgorithmsDemo
{
public class TreeNode<T>
{
public T Data { get; set; }
public List<TreeNode<T>> Children { get; set; }
}
public class Tree<T>
{
public TreeNode<T> Root { get; set; }
}
//
public class BinaryTreeNode<T> : TreeNode<T>
{
public BinaryTreeNode()
{
Children = new List<TreeNode<T>>() { null, null };
}
public BinaryTreeNode<T> Parent { get; set; }
public BinaryTreeNode<T> Left
{
get
{
return (BinaryTreeNode<T>)Children[0];
}
set
{
Children[0] = value;
}
}
public BinaryTreeNode<T> Right
{
get
{
return (BinaryTreeNode<T>)Children[1];
}
set
{
Children[1] = value;
}
}
public int GetHeight()
{
int height = 1;
BinaryTreeNode<T> current = this;
while (current.Parent != null)
{
height++;
current = current.Parent;
}
return height;
}
}
/// <summary>
/// 二叉树遍历类型
/// </summary>
public enum TranversalEnum
{
PREORDER,
INORDER,
POSTORDER,
}
public class BinaryTree<T>
{
public BinaryTreeNode<T> Root { get; set; }
/// <summary>
/// 二叉树所有节点数量
/// </summary>
public int Count { get; set; }
private void TranversePreOrder(BinaryTreeNode<T> node,List<BinaryTreeNode<T>> result)
{
if(node != null)
{
result.Add(node);//前序遍历
TranversePreOrder(node.Left, result);
TranversePreOrder(node.Right, result);
}
}
private void TranverseInOrder(BinaryTreeNode<T> node,List<BinaryTreeNode<T>> result)
{
if(node != null)
{
TranverseInOrder(node.Left, result);
result.Add(node);
TranverseInOrder(node.Right, result);
}
}
private void TranversePostOrder(BinaryTreeNode<T>node,List<BinaryTreeNode<T>> result)
{
if(node != null)
{
TranversePostOrder(node.Left,result);
TranversePostOrder(node.Right, result);
result.Add(node);
}
}
/// <summary>
/// 遍历
/// </summary>
/// <param name="mode"></param>
/// <returns></returns>
public List<BinaryTreeNode<T>> Tranverse(TranversalEnum mode)
{
List<BinaryTreeNode<T>> nodes = new List<BinaryTreeNode<T>>();
switch (mode)
{
case TranversalEnum.PREORDER:
TranversePreOrder(Root, nodes);
break;
case TranversalEnum.INORDER:
TranverseInOrder(Root, nodes);
break;
case TranversalEnum.POSTORDER:
TranversePostOrder(Root, nodes);
break;
}
return nodes;
}
public int GetHeight()
{
int height = 0;
foreach(var node in Tranverse(TranversalEnum.PREORDER))
{
height = Math.Max(height, node.GetHeight());
}
return height;
}
}
public class BinarySearchTree<T> : BinaryTree<T> where T:IComparable
{
/// <summary>
/// 可视化,列宽度
/// </summary>
public static int ColumnWidth = 5;
public bool Contains(T data)
{
BinaryTreeNode<T> node = Root;
while(node != null)
{
int result = data.CompareTo(node.Data);
if (result == 0)
{
return true;
}
else if (result < 0)
{
node = node.Left;
}
else
{
node = node.Right;
}
}
return false;
}
private BinaryTreeNode<T> GetParentForNewNode(T data)
{
BinaryTreeNode<T> current = Root;
BinaryTreeNode<T> parent = null;
while(current != null)
{
parent = current;
int result = data.CompareTo(current.Data);
if (result == 0)
{
throw new ArgumentException($"The node {data} already exists");
}
else if (result < 0)
{
current = current.Left;
}
else
{
current = current.Right;
}
}
return parent;
}
public void Add(T data)
{
BinaryTreeNode<T> parent=GetParentForNewNode(data);
BinaryTreeNode<T> node = new BinaryTreeNode<T>() { Data=data,Parent=parent};
if (parent == null)
{
Root = node;
}
else if (data.CompareTo(parent.Data) < 0)
{
parent.Left = node;
}
else
{
parent.Right = node;
}
Count++;
}
public void Remove(T data)
{
Remove(Root, data);
}
/// <summary>
/// 从以根节点未node的树中,移除含有data的节点
/// </summary>
/// <param name="node"></param>
/// <param name="data"></param>
/// <exception cref="ArgumentException"></exception>
private void Remove(BinaryTreeNode<T> node,T data)
{
if (node == null)
{
throw new ArgumentException($"The node {data} does not exist");
}
else if (data.CompareTo(node.Data) < 0)
{
Remove(node.Left, data);
}
else if (data.CompareTo(node.Data) > 0)
{
Remove(node.Right, data);
}
else //移除的节点找到了
{
if(node.Left==null && node.Right == null)
{
//是叶节点,将该节点替换为null
ReplaceInParent(node, null);
Count--;
}
else if (node.Right == null)
{
//右节点为空,用该节点的左节点替换该节点
ReplaceInParent(node,node.Left);
Count--;
}
else if (node.Left == null)
{
//左节点为空,用改节点的右节点替换该节点
ReplaceInParent(node, node.Right);
Count--;
}
else
{
//左右节点都不为空,找到以该节点的右节点为根节点的子树的最小节点,
//将上述最小节点的值替换到该节点的值,然后再移除最小节点上的数据。
BinaryTreeNode<T> succor = FindMininumInSubTree(node.Right);
//succor的左节点一定是null,后续Remove方法,一定进入左节点是空的分支。
node.Data=succor.Data;
Remove(succor, succor.Data);//
}
}
}
/// <summary>
/// 替换节点,删除node,用newNode来替换node
/// </summary>
/// <param name="node"></param>
/// <param name="newNode"></param>
private void ReplaceInParent(BinaryTreeNode<T> node,BinaryTreeNode<T> newNode)
{
//首先变更node.Parent中含有的对node的信息
if (node.Parent != null)
{
if (node.Parent.Left == node)
{
node.Parent.Left = newNode;
}
else
{
node.Parent.Right = newNode;
}
}
else
{
Root = newNode;
}
//再变更newNode中有关Parent的信息
if(newNode != null)
{
newNode.Parent = node.Parent;
}
}
/// <summary>
/// 找到以node为根节点的子树的最小节点
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
private BinaryTreeNode<T> FindMininumInSubTree(BinaryTreeNode<T> node)
{
while(node.Left != null)
{
node= node.Left;
}
return node;
}
public void Visualize(string caption)
{
char[][] console = InitializeVisualization(out int width);
VisualizeNode(Root, 0, width / 2, console, width);
Console.WriteLine(caption);
foreach (char[] row in console)
{
Console.WriteLine(row);
}
}
private char[][] InitializeVisualization(out int width)
{
int height = this.GetHeight();
width = (int)Math.Pow(2, height) - 1;//最底部的宽度
char[][] console = new char[height*2][];//2倍树高的高度
for(int i = 0; i < height * 2; i++)
{
console[i] = new char[ColumnWidth * width];
}
return console;
}
private void VisualizeNode(BinaryTreeNode<T> node,int row,int column, char[][] console,int width)
{
if(node != null)
{
char[] chars = node.Data.ToString().ToCharArray();
int margin = (ColumnWidth - chars.Length) / 2;
for(int i = 0; i < chars.Length; i++)
{
console[row][ColumnWidth * column + i + margin] = chars[i];
}
int columnDelta = (width + 1) / (int)Math.Pow(2,node.GetHeight()+1);
VisualizeNode(node.Left, row + 2, column - columnDelta, console, width);
VisualizeNode(node.Right, row + 2,column+columnDelta,console,width);
}
}
}
}
#####
愿你一寸一寸地攻城略地,一点一点地焕然一新
#####
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
2022-09-03 C#之依赖注入DI(DependencyInjection)