欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Qt實現(xiàn)的自定義樹結(jié)構(gòu)容器

 更新時間:2024年12月02日 11:27:32   作者:極客晨風(fēng)  
在Qt框架中,盡管其提供了許多強(qiáng)大的容器類,但缺少一個通用的、靈活的樹結(jié)構(gòu)容器,所以本文將設(shè)計并實現(xiàn)一個可復(fù)用的自定義樹結(jié)構(gòu)容器,需要的可以參考下

在Qt框架中,盡管其提供了許多強(qiáng)大的容器類(如 QListQMapQTreeWidget 等),但缺少一個通用的、靈活的樹結(jié)構(gòu)容器,直接支持多層級數(shù)據(jù)管理。為了滿足這些需求,本文設(shè)計并實現(xiàn)了一個可復(fù)用的自定義樹結(jié)構(gòu)容器,并討論其在不同項目中的應(yīng)用。

1. 背景與動機(jī)

樹結(jié)構(gòu)在軟件開發(fā)中是常見的數(shù)據(jù)組織形式,常用于以下場景:

  • 多層級文件管理器:文件夾與文件的樹形展示。
  • 層次化關(guān)系管理:如公司組織結(jié)構(gòu)、任務(wù)依賴關(guān)系。
  • 數(shù)據(jù)處理與分類:如屬性分類、規(guī)則樹等。

然而,Qt 中缺少直接的樹結(jié)構(gòu)容器(QTreeWidget 是 UI 組件,QAbstractItemModel 偏向于數(shù)據(jù)視圖)。因此,我們實現(xiàn)了一個靈活、可擴(kuò)展的 通用樹結(jié)構(gòu)容器,支持:

  • 動態(tài)添加和刪除節(jié)點。
  • 為節(jié)點附加數(shù)據(jù)。
  • 數(shù)據(jù)篩選與查找。
  • 清晰的樹形結(jié)構(gòu)打印與調(diào)試。

2. 核心設(shè)計與實現(xiàn)

2.1 類設(shè)計概覽

該樹容器包含兩個核心類:

TreeNode:

  • 表示樹的單個節(jié)點。
  • 包括節(jié)點名稱、父節(jié)點指針、子節(jié)點列表、節(jié)點數(shù)據(jù)。
  • 支持節(jié)點添加、刪除、數(shù)據(jù)設(shè)置與清除等基本操作。

Tree:

  • 管理整個樹的邏輯。
  • 提供全局的節(jié)點操作接口,如添加、刪除節(jié)點,篩選節(jié)點數(shù)據(jù),打印樹結(jié)構(gòu)等。

2.2 TreeNode 類實現(xiàn)

TreeNode 是樹結(jié)構(gòu)的核心,負(fù)責(zé)管理節(jié)點的層次關(guān)系和數(shù)據(jù)存儲。以下是其關(guān)鍵代碼邏輯:

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

    // 添加子節(jié)點
    TreeNode* addChild(const QString& name);

    // 移除子節(jié)點
    bool removeChild(TreeNode* child);

    // 設(shè)置與清除節(jié)點數(shù)據(jù)
    void setData(const QVariant& data);
    void clearData();

    // 獲取節(jié)點信息
    QVariant getData() const;
    const QList<TreeNode*>& getChildren() const;
    QString getName() const;
    TreeNode* getParent() const;
};

主要功能:

  • addChild 和 removeChild 實現(xiàn)樹的動態(tài)結(jié)構(gòu)調(diào)整。
  • setData 和 clearData 支持靈活的節(jié)點數(shù)據(jù)管理。
  • 提供對父子關(guān)系和數(shù)據(jù)的訪問接口。

2.3 Tree 類實現(xiàn)

Tree 是一個樹容器的管理類。其設(shè)計目標(biāo)是:

  • 提供用戶友好的接口,隱藏樹節(jié)點的內(nèi)部操作。
  • 支持全局的增刪改查功能。

以下是 Tree 類的部分接口說明:

class Tree {
public:
    Tree();
    ~Tree();

    // 節(jié)點操作
    TreeNode* addNode(TreeNode* parent, const QString& name);
    bool removeNode(TreeNode* node);

    // 數(shù)據(jù)操作
    void setNodeData(TreeNode* node, const QVariant& data);
    QVariant getNodeData(TreeNode* node) const;
    void clearNodeData(TreeNode* node);

    // 數(shù)據(jù)篩選與樹形打印
    QList<TreeNode*> filterNodes(const QString& keyword) const;
    void printTree() const;
};

主要功能:

  • addNode:動態(tài)添加節(jié)點,支持將節(jié)點默認(rèn)添加到根節(jié)點。
  • ilterNodes:通過關(guān)鍵字查找包含特定數(shù)據(jù)的節(jié)點。
  • printTree:以層級縮進(jìn)格式打印樹的結(jié)構(gòu),便于調(diào)試。

2.4 調(diào)用示例

以下是使用 Tree 和 TreeNode 的示例代碼:

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

    // 創(chuàng)建樹容器
    Tree tree;

    // 添加節(jié)點
    TreeNode* root = tree.addNode(nullptr, tc("根節(jié)點"));
    TreeNode* nodeA = tree.addNode(root, tc("節(jié)點A"));
    TreeNode* nodeB = tree.addNode(root, tc("節(jié)點B"));
    TreeNode* nodeC = tree.addNode(nodeA, tc("節(jié)點C"));

    // 設(shè)置節(jié)點數(shù)據(jù)
    tree.setNodeData(nodeA, tc("溫度過高"));
    tree.setNodeData(nodeB, tc("正常"));
    tree.setNodeData(nodeC, tc("壓力過低"));

    // 打印樹結(jié)構(gòu)
    tree.printTree();

    // 篩選包含 "溫度" 的節(jié)點
    QList<TreeNode*> filteredNodes = tree.filterNodes(tc("溫度"));
    qDebug() << tc("篩選結(jié)果:");
    for (TreeNode* node : filteredNodes) {
        qDebug() << node->getName() << ":" << node->getData().toString();
    }

    return a.exec();
}

運(yùn)行結(jié)果:

根節(jié)點 ()
  節(jié)點A (溫度過高)
    節(jié)點C (壓力過低)
  節(jié)點B (正常)

篩選結(jié)果:
"節(jié)點A" : "溫度過高"

3. 適用場景分析

該樹容器的靈活性使其適用于多種場景,包括但不限于以下項目:

文件管理器:

  • 以層次結(jié)構(gòu)管理文件夾和文件。
  • 節(jié)點數(shù)據(jù)可存儲文件的元信息(如路徑、大小)。

組織結(jié)構(gòu)管理:

  • 用于顯示公司組織架構(gòu)(如部門、員工)。
  • 節(jié)點數(shù)據(jù)可附加員工信息。

規(guī)則引擎或決策樹:

  • 用于實現(xiàn)條件匹配規(guī)則。
  • 節(jié)點存儲規(guī)則條件與結(jié)果。

動態(tài)數(shù)據(jù)分類:

  • 實現(xiàn)類似標(biāo)簽分類的功能。
  • 支持實時增刪節(jié)點。

調(diào)試工具:

用于顯示復(fù)雜系統(tǒng)中的內(nèi)部數(shù)據(jù)關(guān)系。

4. 優(yōu)勢與改進(jìn)方向

4.1 優(yōu)勢

簡單易用:

  • 接口友好,隱藏復(fù)雜的內(nèi)部操作。
  • 提供清晰的錯誤提示和默認(rèn)行為。

高擴(kuò)展性:

可以輕松添加新功能,如節(jié)點排序、自定義過濾條件等。

靈活性:

節(jié)點的數(shù)據(jù)類型為 QVariant,支持多種數(shù)據(jù)類型存儲。

跨平臺支持:

依賴 Qt 框架,具備良好的跨平臺能力。

4.2 改進(jìn)方向

線程安全:

增加對并發(fā)操作的支持,例如通過 QMutex 實現(xiàn)線程同步。

持久化:

增加樹結(jié)構(gòu)的序列化和反序列化功能,用于存儲和加載數(shù)據(jù)。

性能優(yōu)化:

對大規(guī)模樹操作(如深度遍歷)進(jìn)行優(yōu)化。

模型綁定:

將樹容器與 QAbstractItemModel 綁定,支持直接用于 Qt 的視圖類(如 QTreeView)。

5. 結(jié)語

本文介紹了一個基于 Qt 實現(xiàn)的自定義樹結(jié)構(gòu)容器,其功能涵蓋了節(jié)點管理、數(shù)據(jù)存儲、篩選與打印等操作,適用于多種項目場景。通過該容器,開發(fā)者可以更加靈活地管理復(fù)雜的層次化數(shù)據(jù),同時其清晰的接口設(shè)計也便于擴(kuò)展與維護(hù)。

6. 源碼

以下是修正后的完整代碼實現(xiàn),包含 TreeNode.h、TreeNode.cpp、Tree.h、Tree.cpp 和 main.cpp 文件。代碼修復(fù)了根節(jié)點初始化問題,并增強(qiáng)了錯誤處理和默認(rèn)邏輯。

TreeNode.h

#ifndef TREENODE_H
#define TREENODE_H

#include <QString>
#include <QList>
#include <QVariant>

#define tc(a) QString::fromLocal8Bit(a)

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

    // 添加子節(jié)點
    TreeNode* addChild(const QString& name);

    // 移除子節(jié)點
    bool removeChild(TreeNode* child);

    // 設(shè)置節(jié)點數(shù)據(jù)
    void setData(const QVariant& data);

    // 獲取節(jié)點數(shù)據(jù)
    QVariant getData() const;

    // 移除節(jié)點數(shù)據(jù)
    void clearData();

    // 獲取所有子節(jié)點
    const QList<TreeNode*>& getChildren() const;

    // 獲取節(jié)點名稱
    QString getName() const;

    // 獲取父節(jié)點
    TreeNode* getParent() const;

    // 檢查是否為葉子節(jié)點
    bool isLeaf() const;

private:
    QString nodeName;             // 節(jié)點名稱
    QVariant nodeData;            // 節(jié)點數(shù)據(jù)
    TreeNode* parentNode;         // 父節(jié)點
    QList<TreeNode*> childNodes;  // 子節(jié)點列表
};

#endif // TREENODE_H

TreeNode.cpp

#include "TreeNode.h"
#include <QDebug>

TreeNode::TreeNode(const QString& name, TreeNode* parent)
    : nodeName(name), parentNode(parent) {}

TreeNode::~TreeNode() {
    qDeleteAll(childNodes); // 刪除所有子節(jié)點
}

TreeNode* TreeNode::addChild(const QString& name) {
    TreeNode* child = new TreeNode(name, this);
    childNodes.append(child);
    return child;
}

bool TreeNode::removeChild(TreeNode* child) {
    if (!child || !childNodes.contains(child)) {
        qWarning() << tc("移除失敗:節(jié)點不存在!");
        return false;
    }
    childNodes.removeAll(child);
    delete child; // 刪除子節(jié)點及其數(shù)據(jù)
    return true;
}

void TreeNode::setData(const QVariant& data) {
    nodeData = data;
}

QVariant TreeNode::getData() const {
    return nodeData;
}

void TreeNode::clearData() {
    nodeData.clear();
}

const QList<TreeNode*>& TreeNode::getChildren() const {
    return childNodes;
}

QString TreeNode::getName() const {
    return nodeName;
}

TreeNode* TreeNode::getParent() const {
    return parentNode;
}

bool TreeNode::isLeaf() const {
    return childNodes.isEmpty();
}

Tree.h

#ifndef TREE_H
#define TREE_H

#include "TreeNode.h"

class Tree {
public:
    Tree();
    ~Tree();

    // 添加節(jié)點
    TreeNode* addNode(TreeNode* parent, const QString& name);

    // 移除節(jié)點
    bool removeNode(TreeNode* node);

    // 設(shè)置節(jié)點數(shù)據(jù)
    void setNodeData(TreeNode* node, const QVariant& data);

    // 獲取節(jié)點數(shù)據(jù)
    QVariant getNodeData(TreeNode* node) const;

    // 移除節(jié)點數(shù)據(jù)
    void clearNodeData(TreeNode* node);

    // 查找節(jié)點(通過名稱)
    TreeNode* findNode(TreeNode* root, const QString& name) const;

    // 過濾節(jié)點(通過數(shù)據(jù)關(guān)鍵字)
    QList<TreeNode*> filterNodes(const QString& keyword) const;

    // 打印樹結(jié)構(gòu)
    void printTree() const;

private:
    TreeNode* root;

    // 輔助遞歸方法
    void filterRecursive(TreeNode* node, const QString& keyword, QList<TreeNode*>& result) const;
    void printRecursive(TreeNode* node, int depth) const;
};

#endif // TREE_H

Tree.cpp

#include "Tree.h"
#include <QDebug>

Tree::Tree() {
    root = new TreeNode(tc("根節(jié)點"));
    qDebug() << tc("成功初始化根節(jié)點。");
}

Tree::~Tree() {
    delete root; // 自動刪除所有節(jié)點
}

TreeNode* Tree::addNode(TreeNode* parent, const QString& name) {
    if (!parent) {
        if (!root) {
            qWarning() << tc("添加失?。焊?jié)點未創(chuàng)建!");
            return nullptr;
        }
        qDebug() << tc("未指定父節(jié)點,默認(rèn)添加到根節(jié)點。");
        parent = root; // 如果父節(jié)點為空,默認(rèn)添加到根節(jié)點
    }
    return parent->addChild(name);
}

bool Tree::removeNode(TreeNode* node) {
    if (!node || node == root) {
        qWarning() << tc("移除失敗:節(jié)點為空或為根節(jié)點!");
        return false;
    }
    TreeNode* parent = node->getParent();
    if (!parent) {
        qWarning() << tc("移除失敗:父節(jié)點為空!");
        return false;
    }
    return parent->removeChild(node);
}

void Tree::setNodeData(TreeNode* node, const QVariant& data) {
    if (!node) {
        qWarning() << tc("設(shè)置失敗:節(jié)點為空!");
        return;
    }
    node->setData(data);
}

QVariant Tree::getNodeData(TreeNode* node) const {
    if (!node) {
        qWarning() << tc("獲取失敗:節(jié)點為空!");
        return QVariant();
    }
    return node->getData();
}

void Tree::clearNodeData(TreeNode* node) {
    if (!node) {
        qWarning() << tc("清除失敗:節(jié)點為空!");
        return;
    }
    node->clearData();
}

TreeNode* Tree::findNode(TreeNode* root, const QString& name) const {
    if (!root) return nullptr;
    if (root->getName() == name) return root;

    for (TreeNode* child : root->getChildren()) {
        TreeNode* found = findNode(child, name);
        if (found) return found;
    }
    return nullptr;
}

QList<TreeNode*> Tree::filterNodes(const QString& keyword) const {
    QList<TreeNode*> result;
    filterRecursive(root, keyword, result);
    return result;
}

void Tree::filterRecursive(TreeNode* node, const QString& keyword, QList<TreeNode*>& result) const {
    if (node->getData().toString().contains(keyword)) {
        result.append(node);
    }
    for (TreeNode* child : node->getChildren()) {
        filterRecursive(child, keyword, result);
    }
}

void Tree::printTree() const {
    printRecursive(root, 0);
}

void Tree::printRecursive(TreeNode* node, int depth) const {
    qDebug().noquote() << QString(depth * 2, ' ') + node->getName() + " (" + node->getData().toString() + ")";
    for (TreeNode* child : node->getChildren()) {
        printRecursive(child, depth + 1);
    }
}

main.cpp

#include <QCoreApplication>
#include "Tree.h"

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

    // 創(chuàng)建樹
    Tree tree;

    // 創(chuàng)建子節(jié)點,明確傳入父節(jié)點
    TreeNode* nodeA = tree.addNode(nullptr, tc("節(jié)點A")); // 默認(rèn)添加到根節(jié)點
    TreeNode* nodeB = tree.addNode(nodeA, tc("節(jié)點B"));
    TreeNode* nodeC = tree.addNode(nodeA, tc("節(jié)點C"));

    // 添加數(shù)據(jù)
    tree.setNodeData(nodeA, tc("溫度過高"));
    tree.setNodeData(nodeB, tc("正常"));
    tree.setNodeData(nodeC, tc("壓力過低"));

    // 獲取數(shù)據(jù)
    qDebug() << tc("節(jié)點A數(shù)據(jù):") << tree.getNodeData(nodeA).toString();

    // 清除數(shù)據(jù)
    tree.clearNodeData(nodeC);

    // 過濾節(jié)點
    QList<TreeNode*> filteredNodes = tree.filterNodes(tc("溫度"));
    qDebug() << tc("過濾結(jié)果:");
    for (TreeNode* node : filteredNodes) {
        qDebug() << node->getName() << ":" << node->getData().toString();
    }

    // 打印樹結(jié)構(gòu)
    tree.printTree();

    return a.exec();
}

運(yùn)行結(jié)果

成功初始化根節(jié)點。
未指定父節(jié)點,默認(rèn)添加到根節(jié)點。
未指定父節(jié)點,默認(rèn)添加到根節(jié)點。
未指定父節(jié)點,默認(rèn)添加到根節(jié)點。
節(jié)點A數(shù)據(jù): "溫度過高"
過濾結(jié)果:
"節(jié)點A" : "溫度過高"
根節(jié)點 ()
  節(jié)點A (溫度過高)
    節(jié)點B (正常)
    節(jié)點C ()

功能總結(jié)

該實現(xiàn)支持樹節(jié)點的 添加、刪除、查詢、過濾,以及節(jié)點數(shù)據(jù)的 設(shè)置、獲取、清除。同時,包含中文提示與日志輸出,邏輯健壯且易于擴(kuò)展。

到此這篇關(guān)于基于Qt實現(xiàn)的自定義樹結(jié)構(gòu)容器的文章就介紹到這了,更多相關(guān)Qt自定義樹結(jié)構(gòu)容器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++實現(xiàn)十進(jìn)制數(shù)轉(zhuǎn)換為二進(jìn)制數(shù)的數(shù)學(xué)算法

    C++實現(xiàn)十進(jìn)制數(shù)轉(zhuǎn)換為二進(jìn)制數(shù)的數(shù)學(xué)算法

    這篇文章和大家分享一下我個人對十進(jìn)制數(shù)轉(zhuǎn)換為二進(jìn)制數(shù)的想法,目前暫時更新只整數(shù)十進(jìn)制的轉(zhuǎn)換,后續(xù)會更新帶有小數(shù)的進(jìn)制轉(zhuǎn)換,代碼使用c++實現(xiàn)
    2021-09-09
  • C++的內(nèi)聯(lián)函數(shù)你了解嗎

    C++的內(nèi)聯(lián)函數(shù)你了解嗎

    這篇文章主要為大家詳細(xì)介紹了C++的內(nèi)聯(lián)函數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • C++友元(Friend)用法實例簡介

    C++友元(Friend)用法實例簡介

    這篇文章主要介紹了C++友元(Friend)用法,對于C++的學(xué)習(xí)來說有很好的參考價值,需要的朋友可以參考下
    2014-08-08
  • VScode編譯C++ 頭文件顯示not found的問題

    VScode編譯C++ 頭文件顯示not found的問題

    這篇文章主要介紹了VScode編譯C++ 頭文件顯示not found的問題,本文給大家分享問題解決方法,通過截圖的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2020-03-03
  • C語言動態(tài)內(nèi)存的分配最全面分析

    C語言動態(tài)內(nèi)存的分配最全面分析

    動態(tài)內(nèi)存是相對靜態(tài)內(nèi)存而言的。所謂動態(tài)和靜態(tài)就是指內(nèi)存的分配方式。動態(tài)內(nèi)存是指在堆上分配的內(nèi)存,而靜態(tài)內(nèi)存是指在棧上分配的內(nèi)存,本文帶你深入探究C語言中動態(tài)內(nèi)存的管理
    2022-08-08
  • C語言詳解實現(xiàn)猜數(shù)字游戲步驟

    C語言詳解實現(xiàn)猜數(shù)字游戲步驟

    猜數(shù)字是興起于英國的益智類小游戲,起源于20世紀(jì)中期,一般由兩個人或多人玩,也可以由一個人和電腦玩。游戲規(guī)則為一方出數(shù)字,一方猜,今天我們來實現(xiàn)這個游戲案例
    2022-07-07
  • Qt中樹形控件Tree Widget的使用方法匯總

    Qt中樹形控件Tree Widget的使用方法匯總

    最近小編在研究Tree Widget樹形控件的相關(guān)知識,這種控件其實有時還是很有用處的,我主要利用的是帶有復(fù)選框的樹形控件,下面通過實例代碼給大家介紹下Qt中樹形控件Tree Widget的一些使用方法,感興趣的朋友一起學(xué)習(xí)吧
    2021-11-11
  • C語言中字符串與各數(shù)值類型之間的轉(zhuǎn)換方法

    C語言中字符串與各數(shù)值類型之間的轉(zhuǎn)換方法

    這篇文章主要介紹了C語言中字符串與各數(shù)值類型之間的轉(zhuǎn)換方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • clion最新激活碼+漢化的步驟詳解(親測可用激活到2089)

    clion最新激活碼+漢化的步驟詳解(親測可用激活到2089)

    這篇文章主要介紹了clion最新版下載安裝+破解+漢化的步驟詳解,本文分步驟給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • 詳談C與C++的函數(shù)聲明中省略參數(shù)的不同意義

    詳談C與C++的函數(shù)聲明中省略參數(shù)的不同意義

    下面小編就為大家分享一篇詳談C與C++的函數(shù)聲明中省略參數(shù)的不同意義,具有非常好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-11-11

最新評論