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. 7. Nginx 工作机制&参数设置(详细讲解说明)

    7. Nginx 工作机制&参数设置(详细讲解说明) @ 目录 7. Nginx 工作机制&参数设置(详细讲解说明) 1. Nginx 当中的 master-worker 机制原理 2 ...

  2. Windows编程----进程:命令行参数

    什么是进程的命令行参数 每个进程在启动(双击exe启动.cmd命令行启动或者由其他程序通过CreateProcess启动)的时候,都会有一个命令行参数给它.命令行的参数以空格区分.这个命令行总是不为空 ...

  3. nodejs 图片添加水印(png, jpeg, jpg, gif)

    同步发布:https://blog.jijian.link/2020-04-17/nodejs-watermark/ nodejs 作为一个脚本语言,图片处理这方面有点弱鸡,无法跟 php 这种本身集 ...

  4. docker Get "https://registry-1.docker.io/v2/": x509: certificate is valid for

    前言 docker 在进行 build 时,报错:Get "https://registry-1.docker.io/v2/": x509: certificate is vali ...

  5. go generate

    介绍 go generate 命令是go 1.4版本里面新添加的一个命令,当运行 go generate 时,它将扫描与当前包相关的源代码文件,找出所有包含 //go:generate 的特殊注释,提 ...

  6. php 配置Gmail 发送邮件 PHPMailer

    hotmail 获取邮箱授权码 准备 首先你应该登陆https://mail.google.com地址,注册一个Gmail邮箱,然后设置开启IMAP访问 打开设置,开启IMAP访问 获取应用专用密码 ...

  7. bug|Git Hooks pre-commit|git 提交代码报错|error: 'describe' 'it' 'expect' is not defined (no-undef)|pre-commit hook failed (add --no-verify to bypass)|

    前言 今天学习 jest 的 vue-test-utils 的配置及使用. 报错原因为 jest 全局变量 git 提交代码报错,使用除了参考链接里的解决方案,正好复习一下之前学习的 Git Hook ...

  8. win10/11 禁用移动热点,无法启用

    将网络重制即可

  9. Delphi 模糊查询和字段查询

    procedure TFrmain.scGPEdit1Change(Sender: TObject); var ASql, AKey: string; //模糊查询和字段查询 const vsql1: ...

  10. 面试题-Java虚拟机

    前言 Java虚拟机部分的题目,是我根据Java Guide的面试突击版本V3.0再整理出来的,其中,我选择了一些比较重要的问题,并重新做出相应回答,并添加了一些比较重要的问题,希望对大家起到一定的帮 ...