C# Tips之目录树

写在前面

C# Tips是博主开启的第一个项目,以C#为示例语言,旨在普及编程技巧、经典算法以及计算机视觉、图形学知识。

树状结构

树状结构能够凸显数据的层次性,其基本单位为结点(Node),和继承关系类似,所有结点只能有唯一的父结点(Parent),而可以有多个子结点(Children),父子关系是树状结构的基本关系。根据下图(3叉树)需要明确树状结构的几个基本概念:

概念含义
根结点(Root)无父结点的结点
叶结点(Leaves)无子结点的结点
N叉树N为所有结点子结点数最大值
层次(Level)根结点层次为1,其他结点层次为其父结点层次+1,如A和B的层次都为2
兄弟结点(Brothers)父结点相同的结点,如A和B

在这里插入图片描述

目录树

VS实现的TreeView(目录树)控件是一种特殊的树状结构,其本身的目的不是为了查找而是为了展示数据,可以当做是多个线性结构(Nodes)的组合,常用的二叉查找树AVL树、红黑树等的树状查找方法不能直接用在目录树上。
目录树
注意:TreeView对象本身代表树的根结点,所以展示的实际根结点也会有父结点,即TreeView对象

点击树结点

这种情况通常发生在需要打开被点击结点对应的文件时。

  1. 如果被点击的结点为叶结点,点击打开对应文件;
  2. 如果被点击的结点非叶结点,实际上其对应的是文件夹而非文件,不做出响应。

首先为TreeView添加NodeMouseClick或NodeMouseDoubleClick事件,事件中的TreeNodeMouseClickEventArgs参数可以直接获取被点击的结点,TreeView的SelectedNode属性也可以获取因为点击被选中的结点,更加推荐后者,在点击后应该判断SelectedNode是否为null再执行其他操作。

树结点搜索

以下代码可以实现两种搜索功能,但只限于最大层次为2的目录树

  1. 当搜索关键词包含于父结点时,搜索结果会展示该父结点下的所有子结点;
  2. 当搜索关键词多次出现在不同父结点的子结点时,搜索结果会展示所有满足条件的子结点及其所属父结点。

将搜索框命名为txtSearch,TreeView对象命名为directoryTree,首先为搜索按钮添加Click事件,在Click事件中添加代码

if (txtSearch.Text == "")
{
    MessageBox.Show("请在搜索框内输入文件名称");
    return;
}
BuildDirectoryTree();
List<TreeNode> nodeList = new List<TreeNode>();
SearchNode(directoryTree.Nodes, txtSearch.Text.ToUpper(), nodeList);
if (nodeList.Count == 0)
{
    MessageBox.Show("未搜索到指定文件!");
}
else
{
    TreeNode[] parents = new TreeNode[directoryTree.Nodes.Count];
    List<TreeNode>[] childrenGroups = new List<TreeNode>[directoryTree.Nodes.Count];
    foreach (TreeNode node in nodeList)
    {
        if (node.Parent == null)
            parents[node.Index] = node;
        else
        {
            if (childrenGroups[node.Parent.Index] == null)
                childrenGroups[node.Parent.Index] = new List<TreeNode>();
            childrenGroups[node.Parent.Index].Add(node);
        }
    }
    directoryTree.Nodes.Clear();
    for (int i = 0; i < parents.Length; i++)
    {
        if (parents[i] != null)
            directoryTree.Nodes.Add(parents[i]);
        else if (childrenGroups[i] != null)
        {
            TreeNode parent = childrenGroups[i][0].Parent;
            parent.Nodes.Clear();
            foreach (TreeNode child in childrenGroups[i])
                parent.Nodes.Add(child);
            directoryTree.Nodes.Add(parent);
        }
    }
    directoryTree.ExpandAll();
    directoryTree.Refresh();
}

其中,BuildDirectoryTree方法是重新构建目录树,也就是在每次搜索前都需要将目录树还原到初始状态,SearchNode方法代码如下:

/// <summary>
/// 搜索文件结点,即叶节点
/// </summary>
/// <param name="nodes">搜索树结点</param>
/// <param name="name">搜索名称大写形式</param>
/// <param name="nodeList">保存搜索结果的结点列表</param>
private void SearchNode(TreeNodeCollection nodes, string name, List<TreeNode> nodeList)
{
    if (nodes.Count != 0)
    {
        foreach (TreeNode node in nodes)
        {
            if (node.Text.ToUpper().Contains(name))
                nodeList.Add(node);
            else
                SearchNode(node.Nodes, name, nodeList);
        }
    }
}

搜索1

搜索功能1

在这里插入图片描述

搜索功能2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值