You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TreeView控件基于现有节点最大值获取下一个可用节点名称的实现问题

问题排查

原代码存在以下4个核心问题,导致功能不符合预期且性能不达标:

  • 首分支逻辑反转:if (NodeExistsInSection(treeView, searchFor)) 分支直接返回输入名称,和需求完全相反——需求是节点不存在时直接返回输入名,存在时才需要生成带后缀的新名称。
  • 递归遍历漏判节点:LoopNodesRecursive 仅校验传入节点的子节点文本,未校验节点本身的文本,导致根节点、父层级节点的匹配结果全部被遗漏。
  • 名称生成逻辑低效:采用「后缀累加+逐次全树搜索」的实现方式,后缀数值越大,全树遍历次数越多,若当前最大后缀为500,就需要触发500次全树遍历,性能消耗随后缀数值线性增长。
  • 重复遍历逻辑冗余:NodeExistsInSection 和 SearchRecByText 功能重合度极高,无谓增加了额外的全树遍历开销。
优化方案

核心优化思路为单次全树遍历提取所有匹配前缀的节点后缀,直接计算最大后缀加1,仅需1次全树遍历即可完成全部计算,时间复杂度稳定为O(n),不受后缀数值大小影响,完美适配节点数大于500的场景。
具体规则兼容:

  1. 普通前缀场景:匹配到test、test1~test5时,直接取最大后缀5+1生成test6
  2. 纯数字场景:前缀为空时,匹配到20~30,取最大后缀30+1生成31
修正后完整代码
internal static string GetNextAvailableName(TreeView treeView, string inputName)
{
    // 第一步:拆分输入名称的前缀和初始后缀
    string prefix = inputName;
    int initSuffix = 0;
    var match = Regex.Match(inputName, @"\d+$", RegexOptions.RightToLeft);
    if (match.Success)
    {
        initSuffix = int.Parse(match.Value);
        prefix = inputName.Substring(0, inputName.Length - match.Value.Length);
    }

    // 第二步:单次遍历所有节点,收集所有符合前缀的后缀数值
    int maxSuffix = initSuffix - 1;
    foreach (TreeNode rootNode in treeView.Nodes)
    {
        TraverseAllNodes(rootNode, node =>
        {
            if (node.Text.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
            {
                // 提取后缀数字
                var suffixPart = node.Text.Substring(prefix.Length);
                if (int.TryParse(suffixPart, out int suffix))
                {
                    if (suffix > maxSuffix)
                        maxSuffix = suffix;
                }
                // 处理无前缀的原始名称(比如test,对应后缀为0)
                else if (string.IsNullOrEmpty(suffixPart) && 0 > maxSuffix)
                {
                    maxSuffix = 0;
                }
            }
        });
    }

    // 第三步:生成最终名称
    if (maxSuffix < 0)
        return inputName;
    return maxSuffix == 0 ? $"{prefix}" : $"{prefix}{maxSuffix + 1}";
}

// 递归遍历所有节点的通用方法
private static void TraverseAllNodes(TreeNode currentNode, Action<TreeNode> processNode)
{
    processNode(currentNode);
    foreach (TreeNode childNode in currentNode.Nodes)
    {
        TraverseAllNodes(childNode, processNode);
    }
}

内容的提问来源于stack exchange,提问作者jms2505

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 22:24:00