获取树形结构中,父节点下所有子/孙节点(递归方式)

获取树形结构中,父节点下所有子/孙节点(递归方式)

1 树形结构(TreeItem类)

这里通用型树形结构为TreeItem类,头文件,如下:

#ifndef TREEITEM_H
#define TREEITEM_H

#include <QList>

class TreeItem
{
public:
    explicit TreeItem(QString name, TreeItem *parent = nullptr);
    ~TreeItem();

    void appendChild(TreeItem *item);
    void clearChildren();

    TreeItem *child(int row) { return _children.value(row); }
    QList<TreeItem*> children() { return _children; }
    static QList<TreeItem*> grandchildren(TreeItem* parent);
    QList<TreeItem*> grandchildren();

    TreeItem *parent() { return _parent; }
    int childCount() const { return _children.count(); }
    int row() const { return _row; }
    void setRow(int row){ _row = row; }
    QString name() { return _name; }
    void setName(QString name) { _name = name; }

private:
    TreeItem *_parent;            ///<父节点
    QList<TreeItem*> _children;   ///<子节点列表
    int _row;                     ///<记录本item位于父节点下第几个节点
    QString _name;
};

#endif // TREEITEM_H

源文件,如下:

#include "TreeItem.h"

TreeItem::TreeItem(QString name, TreeItem *parent)
    : _parent(parent),
      _row(0),
      _name(name)
{

}

TreeItem::~TreeItem()
{
    clearChildren();
}

/**
 * @brief TreeItem::appendChild
 * 在此节点下增加子节点
 * @param child 节点
 */
void TreeItem::appendChild(TreeItem *item)
{
    item->setRow(_children.size());   // item存自己是第几个,可以优化效率
    _children.append(item);
}

/**
 * @brief TreeItem::clearChildren
 * 清空所有子节点
 */
void TreeItem::clearChildren()
{
    qDeleteAll(_children);
    _children.clear();
}

/**
 * @brief TreeItem::grandchildren
 * 获取指定父节点parent下的所有子节点(递归包括孙子、重孙子节点)
 * @param parent 父节点
 * @return 子节点列表
 */
QList<TreeItem*> TreeItem::grandchildren(TreeItem* parent)
{
    if (parent->childCount() == 0)
    {
        return QList<TreeItem*>();
    }
    QList<TreeItem*> listItems;
    listItems << parent->children();
    foreach (auto child, parent->children())
    {
        listItems << child->grandchildren(child);
    }
    return listItems;
}

/**
 * @brief TreeItem::grandchildren
 * 获取当前节点下的所有子节点(递归包括孙子、重孙子节点)
 * @return 子节点列表
 */
QList<TreeItem*> TreeItem::grandchildren()
{
    return grandchildren(this);
}

这个类的函数比较简单,就是利用TreeItem类型,彼此依次添加,就可以形成树形结构。
这里需要关注的关键函数为:

QList<TreeItem*> TreeItem::grandchildren(TreeItem* parent)
{
    if (parent->childCount() == 0)
    {
        return QList<TreeItem*>();
    }
    QList<TreeItem*> listItems;
    listItems << parent->children();
    foreach (auto child, parent->children())
    {
        listItems << child->grandchildren(child);
    }
    return listItems;
}

QList<TreeItem*> TreeItem::grandchildren()
{
    return grandchildren(this);
}

利用了递归方式,对形参parent节点下的所有节点进行遍历,并将该parent节点下所有子/孙节点,全部添加到一个List中,并返回给调用者。

2 测试代码(main函数)

测试代码,如下所示:

#include <QCoreApplication>
#include <QDebug>
#include "TreeItem.h"

void print(QList<TreeItem*> items)
{
    for (int i = 0; i < items.size(); i++)
    {
        QString name = items.at(i)->name();
        qDebug() << "Item" << i << ":" << name;
    }
    qDebug() << "Print Over, Total Item Count :" << items.size();
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    /*
     *                China
     *      /           |                   \
     *   SiChuan      BeiJing            GuangDong
     *   /      \                 /          |         \
     * ChengDu YiBin           GuangZhou  ShenZhen   FoShan
    */
    // 四川
    TreeItem* sichuan = new TreeItem("SiChuan");
    TreeItem* chengdu = new TreeItem("ChengDu");
    TreeItem* yibin = new TreeItem("YiBin");
    sichuan->appendChild(chengdu);
    sichuan->appendChild(yibin);

    // 北京
    TreeItem* beijing = new TreeItem("BeiJing");

    // 广东
    TreeItem* guangdong = new TreeItem("GuangDong");
    TreeItem* guangzhou = new TreeItem("GuangZhou");
    TreeItem* shenzhen = new TreeItem("ShenZhen");
    TreeItem* foshan = new TreeItem("FoShan");
    guangdong->appendChild(guangzhou);
    guangdong->appendChild(shenzhen);
    guangdong->appendChild(foshan);

    // China
    TreeItem* china = new TreeItem("China");
    china->appendChild(sichuan);
    china->appendChild(beijing);
    china->appendChild(guangdong);

    // 查看China下所有节点
    QList<TreeItem*> items = china->grandchildren();
    print(items);

    // 查看SiChuan下所有节点
    items = sichuan->grandchildren();
    print(items);

    // 查看GuangDong下所有节点
    items = TreeItem::grandchildren(guangdong);
    print(items);

	delete china; // 仅需删除根节点对象
    return a.exec();
}

该测试代码,首先生成一个,如下图所示的树形结构:
在这里插入图片描述

3 运行效果

最后,分别打印输出China、SiChuan、GuangDong节点下的所有子/孙节点名称。

在这里插入图片描述

需要注意
最后释放内存时,仅需删除根节点对象(china)即可,在析构函数中,会自动依次删除所有子/孙节点内存。

具体工程代码,详见:https://gitee.com/bailiyang/cdemo/tree/master/Qt/67TreeDataTest/TreeDataTest

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

百里杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值