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);
}
}
} }

C#数据结构之Tree的更多相关文章

  1. Mysql存储引擎之TokuDB以及它的数据结构Fractal tree(分形树)

    在目前的Mysql数据库中,使用最广泛的是innodb存储引擎.innodb确实是个很不错的存储引擎,就连高性能Mysql里都说了,如果不是有什么很特别的要求,innodb就是最好的选择.当然,这偏文 ...

  2. 泛函编程(8)-数据结构-Tree

    上节介绍了泛函数据结构List及相关的泛函编程函数设计使用,还附带了少许多态类型(Polymorphic Type)及变形(Type Variance)的介绍.有关Polymorphism的详细介绍会 ...

  3. 深入理解Mysql索引的底层数据结构 B+ Tree (2)

    sql查询 explain的详细用法 操作时间:寻道时间+旋转时间 引入索引:采用二叉树结构 把第二列做为索引生成二叉树结构,此时查询89 只做了两次io操作 但是mysql 为什么不用二叉树作为底层 ...

  4. 数据结构----二叉树Tree和排序二叉树

    二叉树 节点定义 class Node(object): def __init__(self, item): self.item = item self.left = None self.right ...

  5. 深入理解Mysql索引的底层数据结构 B+ Tree (1)

    关键字的个数等于路的个数减1. 一个二叉树节点可以存储4kb大小的数据,假如关键字是整型的一个关键字占用4byte,其他数据冗余4个字节 4 kb = 4*1024 byte = 4096 byte. ...

  6. php常用数据结构

    # 常用数据结构--------------------------------------------------------------------------------## 树(Tree)- ...

  7. HDU2966 In case of failure(浅谈k-d tree)

    嘟嘟嘟 题意:给定\(n\)个二维平面上的点\((x_i, y_i)\),求离每一个点最近的点得距离的平方.(\(n \leqslant 1e5\)) 这就是k-d tree入门题了. k-d tre ...

  8. 常用数据结构的功能及复杂度总结(OI)

    不定长数组 维护一个序列 在末尾插入/删除均摊O(1) 任意位置插入O(n) 指定位置查询/修改O(1) 空间O(n) 链表 维护一个序列 定位到第i个位置O(n) 在任意位置(已定位到该位置)插入/ ...

  9. Mysql联合索引的最左前缀原则以及b+tree

    软件版本mysql5.7 根据官网的文档 https://dev.mysql.com/doc/refman/5.7/en/multiple-column-indexes.html 查询条件要符合最左原 ...

  10. 一步一步分析Gin框架路由源码及radix tree基数树

    Gin 简介 Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much ...

随机推荐

  1. Processing模拟控制多台舵机-以距离为参数 程序参考

    又是一次课程学习的结束,辅导学生的过程也很受益,温故而知新.该组同学需要Arduino控制多达6个舵机,而且基于距离这一参数,在不同距离值之间会有不同的触发事件,也就是6个舵机转的角度都有所不同,而且 ...

  2. 单页应用(SPA)是什么?

    来源:https://zhuanlan.zhihu.com/p/648113861 概述 单页应用(SPA,Single Page Application)是一种网页应用或网站的设计模式,它在浏览器中 ...

  3. 分布式锁—4.Redisson的联锁和红锁

    大纲 1.Redisson联锁MultiLock概述 2.Redisson联锁MultiLock的加锁与释放锁 3.Redisson红锁RedLock的算法原理 4.Redisson红锁RedLock ...

  4. jmespath 使用及案例

    什么是jmespath jmespath 是python里面的一个库 主要在httprunner框架里使用 2.使用语法 列表: with_jmespath(jmes_path,var_name) m ...

  5. 通过 C# 打印Word文档

    Word文档是日常办公和学习中不可或缺的一部分.比如在商务往来中,经常需要打印 Word 文档用于撰写和传递正式的商务信函.合作协议.项目提案等.打印出来的文档便于双方签字盖章,具有法律效力和正式性. ...

  6. nuclei安装使用

    go环境安装 go 下载路径:https://golang.google.cn/dl/ 1.双击 go1.20.7.windows-amd64.msi 2.点击下一步 3.我同意,然后下一步. 4.选 ...

  7. SICK Ranger3源码分析——断线重连

    前言 本文可在https://paw5zx.github.io/SICK-Ranger3-source-code-analysis-01/中阅读,体验更加 简单分析一下SICK Ranger3源码中断 ...

  8. c++中的类成员函数指针

    c++中的类成员函数指针 文章目录 c++中的类成员函数指针 发生的事情 正常的函数指针定义 定义类的成员函数指针 std::function 发生的事情 最近,想用一个QMap来创建字符串和一个函数 ...

  9. 如何写自己的springboot starter?自动装配原理是什么?

    如何写自己的springboot starter?自动装配原理是什么? 官方文档地址:https://docs.spring.io/spring-boot/docs/2.6.13/reference/ ...

  10. Vmware ESXi 是免费吗?一文弄懂vSphere功能特性及ESXi与vSphere到底有什么区别和联系。

    目录 收起 一.对VMware vSphere及ESXi的相关疑问 1.Vmware vSphere 有些什么功能? 2.ESXi 是否真正免费? 3. ESXi 和 vSphere 到底有什么区别, ...