C# 从数据表结构计算前序树遍历

C# 从数据表结构计算前序树遍历,c#,modified-preorder-tree-t,C#,Modified Preorder Tree T,我有一个具有以下结构的数据表: Root | Level 1 | Level 2 | Level 3 | Tree L | Tree R Food 1 18 Fruit 2 11 Red 3 6 Cherry

我有一个具有以下结构的数据表:

Root | Level 1 | Level 2 | Level 3 | Tree L | Tree R
Food                                 1        18
       Fruit                         2        11
                 Red                 3        6
                           Cherry    4        5
                 Yellow              7        10
                           Banana    8        9
       Meat                          12       17
                 Beef                13       14
                 Pork                15       16
使用C#,我需要遍历此结构并为每个节点计算正确的树L和树R值。这只是一个例子,真实的结构有几百个节点,至少达到7级,但可能更多


有人能建议我如何使用代码来计算左右值吗?

因此,您希望跟踪树的访问顺序,但您将顺序分为
L
R
。这些对应于
节点
结构的
访问
功能的“入口”和“出口”。假设
节点
类具有
节点.Visit()
方法,则可以:

private static List<Tuple<char,Node>> VisitOrder = new List<Tuple<char,Node>>();

public void Visit()
{
    VisitOrder.Add(Tuple.Create('L', this));
    // whatever visit logic you use here
    VisitOrder.Add(Tuple.Create('R', this));
}

以下是我是如何找到答案的:

private class FolderRow
    {
        public int Indent
        {
            get { return this.Row.GetValue("Indent", 0); }
            set { this.Row["Indent"] = value; }
        }
        public int Left
        {
            get { return this.Row.GetValue("Tree L", 0); }
            set { this.Row["Tree L"] = value; }
        }
        public int Right
        {
            get { return this.Row.GetValue("Tree R", 0); }
            set { this.Row["Tree R"] = value; }
        }
        public Guid Id
        {
            get { return this.Row.GetValue("FolderID", Guid.Empty); }

        }
        public DataRow Row { get; private set; }

        public int RowNum { get; set; }

        public bool RowComplete { get { return this.Left > 0 && this.Right > 0; } }

        public FolderRow(DataRow row, int rowNum)
        {
            this.Row = row;
            this.RowNum = rowNum;
        }
    }    

[TestMethod]
public void ImportFolderStructure()
{
    var inputTable = FileUtil.GetDataSetFromExcelFile(new FileInfo(@"c:\SampleTree.xlsx")).Tables[0];

    var currentLevel = 0;
    var nodeCount = 1;
    var currentRow = 0;

    inputTable.Columns.Add("Indent", typeof (int));
    inputTable.Columns.Add("Path", typeof (string));

    var rightStack = new List<FolderRow>();

    foreach (DataRow row in inputTable.Rows)
        row["Indent"] = GetLevelPopulated(row);

    foreach (DataRow row in inputTable.Rows)
    {
        if (row.GetValue("Indent", 0) == 0)
            row["Tree L"] = 1;                

    }

    while (true)
    {
        var row = GetRow(inputTable, currentRow);
        if (row.Indent == 0)
        {
            currentRow++;
            rightStack.Add(row);
            continue; 
        }

        // if the indent of this row is greater than the previous row ...
        if (row.Indent > currentLevel)
        {
            currentLevel++;
            nodeCount++;
            row.Left = nodeCount;
            // ... check the next row to see if it is further indented
            currentRow = HandleNextRow(row, currentRow, rightStack, inputTable, ref currentLevel, ref nodeCount);
        } else if (row.Indent == currentLevel)
        {
            nodeCount++;
            row.Left = nodeCount;
            currentRow = HandleNextRow(row, currentRow, rightStack, inputTable, ref currentLevel, ref nodeCount);
        } else if (row.Indent < currentLevel)
        {
            currentLevel--;
            nodeCount++;
            row.Left = nodeCount;
            currentRow = HandleNextRow(row, currentRow, rightStack, inputTable, ref currentLevel, ref nodeCount);
        }

        if (inputTable.Rows.Cast<DataRow>().Select(r => new FolderRow(r, -1)).All(r => r.RowComplete))
            break;

    }

}

private int HandleNextRow(FolderRow row, int currentRow, List<FolderRow> rightStack, DataTable inputTable, ref int currentLevel,
                          ref int nodeCount)
{
    var nextRow = GetRow(inputTable, currentRow + 1);
    if (nextRow != null)
    {
        if (nextRow.Indent > row.Indent)
        {
            // ok the current row has a child so we will need to set the tree right of that, add to stack
            rightStack.Add(row);
        }
        else if (nextRow.Indent == row.Indent)
        {
            nodeCount++;
            row.Right = nodeCount;
        }
        else if (nextRow.Indent < row.Indent)
        {
            nodeCount++;
            row.Right = nodeCount;
            nodeCount++;
            // here we need to get the most recently added row to rightStack, set the Right to the current nodeCount
            var stackLast = rightStack.LastOrDefault();
            if (stackLast != null)
            {
                stackLast.Right = nodeCount;
                rightStack.Remove(stackLast);
            }

            currentLevel--;
        }

        currentRow++;

        if (rightStack.Count > 1)
        {
            // before we move on to the next row, we need to check if there is more than one row still in right stack and 
            // the new current row's ident is less than the current branch (not current leaf)
            var newCurrentRow = GetRow(inputTable, currentRow);
            var stackLast = rightStack.LastOrDefault();
            if (newCurrentRow.Indent == stackLast.Indent)
            {
                nodeCount++;
                stackLast.Right = nodeCount;
                rightStack.Remove(stackLast);

            }
        }


    }
    else
    {
        // reached the bottom
        nodeCount++;
        row.Right = nodeCount;

        // loop through the remaining items in rightStack and set their right values
        var stackLast = rightStack.LastOrDefault();
        while (stackLast != null)
        {
            nodeCount++;
            stackLast.Right = nodeCount;
            rightStack.Remove(stackLast);
            stackLast = rightStack.LastOrDefault();
        }
    }
    return currentRow;
}

private FolderRow GetRow(DataTable inputTable, int rowCount)
{
    if (rowCount >= inputTable.Rows.Count)
        return null;

    return rowCount < 0 ? null : new FolderRow(inputTable.Rows[rowCount],rowCount);
}

private int GetLevelPopulated(DataRow row)
{
    var level = 0;

    while (level < 14)
    {
        if (level == 0 && row["Root"] != DBNull.Value)
            return level;

        level++;

        if (row["Level " + level] != DBNull.Value)
            return level;
    }

    return -1;
}
私有类文件夹行
{
公共整数缩进
{
get{返回this.Row.GetValue(“缩进”,0);}
设置{this.Row[“Indent”]=value;}
}
公共整数左
{
get{返回this.Row.GetValue(“树L”,0);}
设置{this.Row[“Tree L”]=value;}
}
公权
{
get{返回this.Row.GetValue(“树R”,0);}
设置{this.Row[“Tree R”]=value;}
}
公共Guid Id
{
get{返回this.Row.GetValue(“FolderID”,Guid.Empty);}
}
公共数据行{get;private set;}
public int RowNum{get;set;}
公共bool行完成{get{返回this.Left>0&&this.Right>0;}
公共文件夹行(DataRow行,int rowNum)
{
this.Row=行;
this.RowNum=RowNum;
}
}    
[测试方法]
public void ImportFolderStructure()
{
var inputable=FileUtil.GetDataSetFromExcelFile(新文件信息(@“c:\SampleTree.xlsx”))。表[0];
var currentLevel=0;
var nodeCount=1;
var currentRow=0;
可输入.Columns.Add(“缩进”,typeof(int));
可输入.Columns.Add(“路径”,类型(字符串));
var rightStack=新列表();
foreach(可输入的.Rows中的数据行)
行[“缩进”]=GetLevelPopulated(行);
foreach(可输入的.Rows中的数据行)
{
if(row.GetValue(“缩进”,0)==0)
行[“树L”]=1;
}
while(true)
{
var row=GetRow(可输入,currentRow);
if(row.Indent==0)
{
currentRow++;
添加(行);
持续
}
//如果此行的缩进大于上一行。。。
如果(行缩进>当前级别)
{
currentLevel++;
nodeCount++;
行左=节点计数;
//…检查下一行是否进一步缩进
currentRow=HandleNextRow(行、currentRow、rightStack、可输入、参考currentLevel、参考nodeCount);
}else if(row.Indent==currentLevel)
{
nodeCount++;
行左=节点计数;
currentRow=HandleNextRow(行、currentRow、rightStack、可输入、参考currentLevel、参考nodeCount);
}else if(行缩进<当前级别)
{
当前级别--;
nodeCount++;
行左=节点计数;
currentRow=HandleNextRow(行、currentRow、rightStack、可输入、参考currentLevel、参考nodeCount);
}
if(inputable.Rows.Cast().Select(r=>newfolderrow(r,-1)).All(r=>r.RowComplete))
打破
}
}
私有int HandleNextRow(FolderRow行、int currentRow行、List rightStack、DataTable可输入、ref int currentLevel、,
ref int节点计数)
{
var nextRow=GetRow(可输入,currentRow+1);
如果(nextRow!=null)
{
如果(下一行缩进>行缩进)
{
//好的,当前行有一个子行,所以我们需要将树设置在它的右边,添加到堆栈
添加(行);
}
else if(nextRow.Indent==行.Indent)
{
nodeCount++;
row.Right=节点计数;
}
否则如果(下一行缩进<行缩进)
{
nodeCount++;
row.Right=节点计数;
nodeCount++;
//在这里,我们需要获取最近添加到rightStack的行,将其设置为当前nodeCount
var stackLast=rightStack.LastOrDefault();
if(stackLast!=null)
{
stackLast.Right=nodeCount;
rightStack.Remove(stackLast);
}
当前级别--;
}
currentRow++;
如果(rightStack.Count>1)
{
//在继续下一行之前,我们需要检查是否有多行仍然在右堆栈中,并且
//新的当前行的标识小于当前分支(不是当前叶)
var newCurrentRow=GetRow(可输入,currentRow);
var stackLast=rightStack.LastOrDefault();
if(newCurrentRow.Indent==stackLast.Indent)
{
nodeCount++;
stackLast.Right=nodeCount;
rightStack.Remove(stackLast);
}
}
}
其他的
{
//跌入谷底
nodeCount++;
row.Right=节点计数;
//循环查看rightStack中的其余项并设置其正确的值
var stackLast=rightStack.LastOrDefault();
while(stackLast!=null)
{
nodeCount++;
stackLast.Right=nodeCount;
rightStack.Remove(stackLast);
stackLast=rightStack.LastOrDefault();
}
}
返回当前行;
}
私有FolderRow GetRow(数据表可输入,整数行计数)
{
if(rowCount>=inputable.Rows.Count)
返回null;
返回rowCount<0?空:新建FolderRow(可输入。Rows[rowCount],rowCount);
}
私有int GetLevelPop
private class FolderRow
    {
        public int Indent
        {
            get { return this.Row.GetValue("Indent", 0); }
            set { this.Row["Indent"] = value; }
        }
        public int Left
        {
            get { return this.Row.GetValue("Tree L", 0); }
            set { this.Row["Tree L"] = value; }
        }
        public int Right
        {
            get { return this.Row.GetValue("Tree R", 0); }
            set { this.Row["Tree R"] = value; }
        }
        public Guid Id
        {
            get { return this.Row.GetValue("FolderID", Guid.Empty); }

        }
        public DataRow Row { get; private set; }

        public int RowNum { get; set; }

        public bool RowComplete { get { return this.Left > 0 && this.Right > 0; } }

        public FolderRow(DataRow row, int rowNum)
        {
            this.Row = row;
            this.RowNum = rowNum;
        }
    }    

[TestMethod]
public void ImportFolderStructure()
{
    var inputTable = FileUtil.GetDataSetFromExcelFile(new FileInfo(@"c:\SampleTree.xlsx")).Tables[0];

    var currentLevel = 0;
    var nodeCount = 1;
    var currentRow = 0;

    inputTable.Columns.Add("Indent", typeof (int));
    inputTable.Columns.Add("Path", typeof (string));

    var rightStack = new List<FolderRow>();

    foreach (DataRow row in inputTable.Rows)
        row["Indent"] = GetLevelPopulated(row);

    foreach (DataRow row in inputTable.Rows)
    {
        if (row.GetValue("Indent", 0) == 0)
            row["Tree L"] = 1;                

    }

    while (true)
    {
        var row = GetRow(inputTable, currentRow);
        if (row.Indent == 0)
        {
            currentRow++;
            rightStack.Add(row);
            continue; 
        }

        // if the indent of this row is greater than the previous row ...
        if (row.Indent > currentLevel)
        {
            currentLevel++;
            nodeCount++;
            row.Left = nodeCount;
            // ... check the next row to see if it is further indented
            currentRow = HandleNextRow(row, currentRow, rightStack, inputTable, ref currentLevel, ref nodeCount);
        } else if (row.Indent == currentLevel)
        {
            nodeCount++;
            row.Left = nodeCount;
            currentRow = HandleNextRow(row, currentRow, rightStack, inputTable, ref currentLevel, ref nodeCount);
        } else if (row.Indent < currentLevel)
        {
            currentLevel--;
            nodeCount++;
            row.Left = nodeCount;
            currentRow = HandleNextRow(row, currentRow, rightStack, inputTable, ref currentLevel, ref nodeCount);
        }

        if (inputTable.Rows.Cast<DataRow>().Select(r => new FolderRow(r, -1)).All(r => r.RowComplete))
            break;

    }

}

private int HandleNextRow(FolderRow row, int currentRow, List<FolderRow> rightStack, DataTable inputTable, ref int currentLevel,
                          ref int nodeCount)
{
    var nextRow = GetRow(inputTable, currentRow + 1);
    if (nextRow != null)
    {
        if (nextRow.Indent > row.Indent)
        {
            // ok the current row has a child so we will need to set the tree right of that, add to stack
            rightStack.Add(row);
        }
        else if (nextRow.Indent == row.Indent)
        {
            nodeCount++;
            row.Right = nodeCount;
        }
        else if (nextRow.Indent < row.Indent)
        {
            nodeCount++;
            row.Right = nodeCount;
            nodeCount++;
            // here we need to get the most recently added row to rightStack, set the Right to the current nodeCount
            var stackLast = rightStack.LastOrDefault();
            if (stackLast != null)
            {
                stackLast.Right = nodeCount;
                rightStack.Remove(stackLast);
            }

            currentLevel--;
        }

        currentRow++;

        if (rightStack.Count > 1)
        {
            // before we move on to the next row, we need to check if there is more than one row still in right stack and 
            // the new current row's ident is less than the current branch (not current leaf)
            var newCurrentRow = GetRow(inputTable, currentRow);
            var stackLast = rightStack.LastOrDefault();
            if (newCurrentRow.Indent == stackLast.Indent)
            {
                nodeCount++;
                stackLast.Right = nodeCount;
                rightStack.Remove(stackLast);

            }
        }


    }
    else
    {
        // reached the bottom
        nodeCount++;
        row.Right = nodeCount;

        // loop through the remaining items in rightStack and set their right values
        var stackLast = rightStack.LastOrDefault();
        while (stackLast != null)
        {
            nodeCount++;
            stackLast.Right = nodeCount;
            rightStack.Remove(stackLast);
            stackLast = rightStack.LastOrDefault();
        }
    }
    return currentRow;
}

private FolderRow GetRow(DataTable inputTable, int rowCount)
{
    if (rowCount >= inputTable.Rows.Count)
        return null;

    return rowCount < 0 ? null : new FolderRow(inputTable.Rows[rowCount],rowCount);
}

private int GetLevelPopulated(DataRow row)
{
    var level = 0;

    while (level < 14)
    {
        if (level == 0 && row["Root"] != DBNull.Value)
            return level;

        level++;

        if (row["Level " + level] != DBNull.Value)
            return level;
    }

    return -1;
}