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);
}
}
}
}
C#数据结构之Tree的更多相关文章
- Mysql存储引擎之TokuDB以及它的数据结构Fractal tree(分形树)
在目前的Mysql数据库中,使用最广泛的是innodb存储引擎.innodb确实是个很不错的存储引擎,就连高性能Mysql里都说了,如果不是有什么很特别的要求,innodb就是最好的选择.当然,这偏文 ...
- 泛函编程(8)-数据结构-Tree
上节介绍了泛函数据结构List及相关的泛函编程函数设计使用,还附带了少许多态类型(Polymorphic Type)及变形(Type Variance)的介绍.有关Polymorphism的详细介绍会 ...
- 深入理解Mysql索引的底层数据结构 B+ Tree (2)
sql查询 explain的详细用法 操作时间:寻道时间+旋转时间 引入索引:采用二叉树结构 把第二列做为索引生成二叉树结构,此时查询89 只做了两次io操作 但是mysql 为什么不用二叉树作为底层 ...
- 数据结构----二叉树Tree和排序二叉树
二叉树 节点定义 class Node(object): def __init__(self, item): self.item = item self.left = None self.right ...
- 深入理解Mysql索引的底层数据结构 B+ Tree (1)
关键字的个数等于路的个数减1. 一个二叉树节点可以存储4kb大小的数据,假如关键字是整型的一个关键字占用4byte,其他数据冗余4个字节 4 kb = 4*1024 byte = 4096 byte. ...
- php常用数据结构
# 常用数据结构--------------------------------------------------------------------------------## 树(Tree)- ...
- HDU2966 In case of failure(浅谈k-d tree)
嘟嘟嘟 题意:给定\(n\)个二维平面上的点\((x_i, y_i)\),求离每一个点最近的点得距离的平方.(\(n \leqslant 1e5\)) 这就是k-d tree入门题了. k-d tre ...
- 常用数据结构的功能及复杂度总结(OI)
不定长数组 维护一个序列 在末尾插入/删除均摊O(1) 任意位置插入O(n) 指定位置查询/修改O(1) 空间O(n) 链表 维护一个序列 定位到第i个位置O(n) 在任意位置(已定位到该位置)插入/ ...
- Mysql联合索引的最左前缀原则以及b+tree
软件版本mysql5.7 根据官网的文档 https://dev.mysql.com/doc/refman/5.7/en/multiple-column-indexes.html 查询条件要符合最左原 ...
- 一步一步分析Gin框架路由源码及radix tree基数树
Gin 简介 Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much ...
随机推荐
- MybatisPlus - [02] HelloWorld
参考:https://www.cnblogs.com/haoxinyue/p/5208136.html(分布式系统唯一ID生成方案汇总) 一.准备工作 (1)创建数据库: create databas ...
- ABC393E题解
大概评级:绿. 拿到题目,寻找突破口,发现 \(A_i \le 10^6\),一般的数据都是 \(A_i \le 10^9\),所以必有蹊跷. 数学,权值,最大公约数,联想到了因子--懂了,原来是这么 ...
- 印度股票实时行情API数据源接口
StockTV API: 提供实时和历史行情数据,覆盖印度所有股票和指数,支持WebSocket和REST API接口.(推荐使用,对接简单,有技术支持) 新浪财经:提供股票市场数据,可以优先考虑 ...
- vue 判断某个时间小于当前时间
如下 new Date().getTime() 获取当前时间(毫秒) 我需要对比的时间为秒,所以需要除于1000 <div v-if="scope.row.created_at < ...
- docker中 启动所有的容器命令
docker中 启动所有的容器命令 docker start $(docker ps -a | awk '{ print $1}' | tail -n +2) docker中 关闭所有的容器命令 ...
- 大型通用电子制造执行系统(MES)
简介: 系统参考西门子MOM智能制造Opcenter工业软件制造执行系统Camstar电子套件人机料法环数据建模业务对象和车间生产执行事务逻辑,采用面向对象分层设计与C#编程开发:包含电子制造企业 ...
- 【python-数据分析】pandas时间序列处理
1. timestamp 1.1 创建timestamp 自定义timestamp 语法:pd.Timestamp(ts_input,tz,year,month,day,hour,minute,sec ...
- Redis 相关
高并发多机的时候,虽然有失效时间,但还是会有短时间内缓存和数据库数据不一致(读操作不需要特殊操作),更新操作的时候先删除缓存,再更新数据库先更新数据库,再删除缓存原子性破坏,增加队列重试 先删除缓存, ...
- MySQL 的 JSON 查询
MySQL 的 JSON 路径格式 MySQL 使用特定的 JSON 路径表达式语法来导航和提取 JSON 文档中的数据 基本结构 MySQL 中的 JSON 路径遵循以下通用格式 $[路径组件] 路 ...
- Random和猜数字小游戏
1.Random:使用方式和Scanner一样 Random用于生成随机数,括号里的10就是指在10以内随机生成一个数(0~9) Random生成的随机数都是从0开头 . 提问:那该如何让Random ...