C# 如何将层次结构列表转换为二叉树
我正在从事一项多层次的营销(二进制)工作,如下所示: (但二叉树不要求是完美的。一个节点可以有0-2个子节点) 我的问题是,我从数据库中获取的数据是平面列表。 请注意,我正在使用(sql server 2014) 基本上,C# 如何将层次结构列表转换为二叉树,c#,asp.net,sql-server,binary-tree,hierarchyid,C#,Asp.net,Sql Server,Binary Tree,Hierarchyid,我正在从事一项多层次的营销(二进制)工作,如下所示: (但二叉树不要求是完美的。一个节点可以有0-2个子节点) 我的问题是,我从数据库中获取的数据是平面列表。 请注意,我正在使用(sql server 2014) 基本上,TextNode列就像面包屑一样 每个斜杠/表示一个级别 如果我将/1/的TextNode作为根。然后,以/1/开头的每个节点都属于该根节点,即/1/、/1/1/和/1/1/(包括根节点,它将是级别0) 我试过这个问题的答案,但它不起作用 如何将平面列表转换为二叉树,以便轻
TextNode
列就像面包屑一样
每个斜杠/
表示一个级别
如果我将/1/
的TextNode作为根。然后,以/1/
开头的每个节点都属于该根节点,即/1/
、/1/1/
和/1/1/
(包括根节点,它将是级别0)
我试过这个问题的答案,但它不起作用
如何将平面列表转换为二叉树,以便轻松遍历并在屏幕上显示它
如果重要的话,我会使用C#、ASP MVC 5、SQL Server 2014。这里是一个非常简单的实现(假设节点顺序正确),可以通过多种方式进行增强
public interface IRow<out T>
{
string TextNode { get; }
T Value { get; }
}
public class TreeNode<T>
{
private struct NodeDescriptor
{
public int Level { get; }
public int ParentIndex { get; }
public NodeDescriptor(IRow<T> row)
{
var split = row.TextNode.Split(new [] {"/"}, StringSplitOptions.RemoveEmptyEntries);
Level = split.Length;
ParentIndex = split.Length > 1 ? int.Parse(split[split.Length - 2]) - 1 : 0;
}
}
public T Value { get; }
public List<TreeNode<T>> Descendants { get; }
private TreeNode(T value)
{
Value = value;
Descendants = new List<TreeNode<T>>();
}
public static TreeNode<T> Parse(IReadOnlyList<IRow<T>> rows)
{
if (rows.Count == 0)
return null;
var result = new TreeNode<T>(rows[0].Value);
FillParents(new[] {result}, rows, 1, 1);
return result;
}
private static void FillParents(IList<TreeNode<T>> parents, IReadOnlyList<IRow<T>> rows, int index, int currentLevel)
{
var result = new List<TreeNode<T>>();
for (int i = index; i < rows.Count; i++)
{
var descriptor = new NodeDescriptor(rows[i]);
if (descriptor.Level != currentLevel)
{
FillParents(result, rows, i, descriptor.Level);
return;
}
var treeNode = new TreeNode<T>(rows[i].Value);
parents[descriptor.ParentIndex].Descendants.Add(treeNode);
result.Add(treeNode);
}
}
}
公共接口IRow
{
字符串TextNode{get;}
T值{get;}
}
公共级树节点
{
私有结构节点描述符
{
公共整数级别{get;}
公共int父索引{get;}
公共节点描述符(IRow行)
{
var split=row.TextNode.split(新[]{”/“},StringSplitOptions.RemoveEmptyEntries);
水平=分割长度;
ParentIndex=split.Length>1?int.Parse(split[split.Length-2])-1:0;
}
}
公共T值{get;}
公共列表子体{get;}
私有树节点(T值)
{
价值=价值;
子体=新列表();
}
公共静态树节点解析(IReadOnlyList行)
{
如果(rows.Count==0)
返回null;
var结果=新树节点(行[0]。值);
填充父对象(新[]{result},行,1,1);
返回结果;
}
私有静态void FillParents(IList父级、IReadOnlyList行、int索引、int currentLevel)
{
var result=新列表();
for(inti=index;i
示例用法:
public class Row : IRow<string>
{
public string TextNode { get; }
public string Value { get; }
public Row(string textNode, string userName)
{
TextNode = textNode;
Value = userName;
}
}
class Program
{
static void Main(string[] args)
{
IRow<string>[] rows =
{
new Row("/", "Ahmed"),
new Row("/1/", "Saeed"),
new Row("/2/", "Amjid"),
new Row("/1/1/", "Noura"),
new Row("/2/1/", "Noura01"),
new Row("/2/2/", "Reem01"),
new Row("/1/1/1", "Under_noura")
};
var tree = TreeNode<string>.Parse(rows);
PrintTree(tree);
}
private static void PrintTree<T>(TreeNode<T> tree, int level = 0)
{
string prefix = new string('-', level*2);
Console.WriteLine("{0}{1}", prefix, tree.Value);
foreach (var node in tree.Descendants)
{
PrintTree(node, level + 1);
}
}
}
公共类行:IRow
{
公共字符串TextNode{get;}
公共字符串值{get;}
公用行(字符串textNode、字符串用户名)
{
TextNode=TextNode;
值=用户名;
}
}
班级计划
{
静态void Main(字符串[]参数)
{
IRow[]行=
{
新行(“/”,“Ahmed”),
新行(“/1/”,“Saeed”),
新行(“/2/”,“Amjid”),
新行(“/1/1/”,“努拉”),
新行(“/2/1/”,“Noura01”),
新行(“/2/2/”,“Reem01”),
新行(“/1/1/1”,“在努拉下”)
};
var tree=TreeNode.Parse(行);
打印树(树);
}
私有静态void打印树(TreeNode树,int级别=0)
{
字符串前缀=新字符串('-',级别*2);
WriteLine(“{0}{1}”,前缀,tree.Value);
foreach(树中的var节点。后代)
{
打印树(节点,级别+1);
}
}
}
我完全按照Alex实现实现了这段代码,但正如在某些情况下提到的,它没有正常工作。。看看我的图片和代码(从Alex post复制的)[数据库中的数据是正确的,但在树状视图中似乎有一些问题]
public class Row : IRow<string>
{
public string TextNode { get; }
public string Value { get; }
public long Id { get; }
public string FIN { get; }
public Row(string textNode, string userName, long id, string fin)
{
FIN = fin;
Id = id;
TextNode = textNode;
Value = userName;
}
}
public interface IRow<out T>
{
string TextNode { get; }
long Id { get; }
string FIN { get; }
T Value { get; }
}
public class TreeNode<T>
{
private struct NodeDescriptor
{
public int Level { get; }
public int ParentIndex { get; }
public NodeDescriptor(IRow<T> row)
{
var split = row.TextNode.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
Level = split.Length;
ParentIndex = split.Length > 1 ? int.Parse(split[split.Length - 2]) - 1 : 0;
}
}
public T title { get; }
public long Id { get; }
public string FIN { get; }
public List<TreeNode<T>> children { get; }
private TreeNode(T value, long id, string fin)
{
Id = id;
FIN = fin;
title = value;
children = new List<TreeNode<T>>();
}
public static TreeNode<T> Parse(IReadOnlyList<IRow<T>> rows)
{
if (rows.Count == 0)
return null;
var result = new TreeNode<T>(rows[0].Value, rows[0].Id, rows[0].FIN);
FillParents(new[] { result }, rows, 1, 1);
return result;
}
private static void FillParents(IList<TreeNode<T>> parents, IReadOnlyList<IRow<T>> rows, int index, int currentLevel)
{
var result = new List<TreeNode<T>>();
for (int i = index; i < rows.Count; i++)
{
var descriptor = new NodeDescriptor(rows[i]);
if (descriptor.Level != currentLevel)
{
FillParents(result, rows, i, descriptor.Level);
return;
}
var treeNode = new TreeNode<T>(rows[i].Value, rows[i].Id, rows[i].FIN);
parents[descriptor.ParentIndex].children.Add(treeNode);
result.Add(treeNode);
}
}
}
有没有这些案例的例子?这个答案有点旧,我可以做得更好,但无论如何它都应该可以工作,只需在解析之前对行进行排序(按
/
的数量升序,然后按字符串值)非常感谢您的后续操作。正如你所说,我已经发布了
{"title":"Earth","Id":32,"FIN":"FIN","children":[{"title":"Europe","Id":33,"FIN":"FIN001","children":[{"title":"France","Id":35,"FIN":"FIN001001","children":[{"title":"Paris","Id":36,"FIN":"FIN001001001","children":[]},{"title":"Brasilia","Id":41,"FIN":"FIN002001001","children":[]},{"title":"Bahia","Id":42,"FIN":"FIN002001002","children":[]}]},{"title":"Spain","Id":38,"FIN":"FIN001002","children":[{"title":"Madrid","Id":37,"FIN":"FIN001002001","children":[{"title":"Salvador","Id":43,"FIN":"FIN002001002001","children":[]}]}]},{"title":"Italy","Id":45,"FIN":"FIN001003","children":[]},{"title":"Germany","Id":48,"FIN":"FIN001004","children":[]},{"title":"test","Id":10049,"FIN":"FIN001005","children":[]}]},{"title":"South America","Id":34,"FIN":"FIN002","children":[{"title":"Brazil","Id":40,"FIN":"FIN002001","children":[{"title":"Morano","Id":47,"FIN":"FIN001003001","children":[]}]}]},{"title":"Antarctica","Id":39,"FIN":"FIN003","children":[{"title":"McMurdo Station","Id":44,"FIN":"FIN003001","children":[]}]}]}