QT C++ 学习之 多叉树

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

经常使用得都是二叉树,今天记录一下多叉树的基本实现步骤,其他的后续慢慢增加。

一、初始化节点结构体

//这里因为想尝试新的方式,没有使用struct作为基础
class DataNode
{
public:
    DataNode *m_parent{nullptr};//节点的父亲
    QString m_data; //节点数据
    QList<DataNode*> m_child_list;//节点的子节点列表
    DataNode(DataNode* parent, QString data) {m_parent = parent; m_data = data;}//节点的构造方法
};

二、初始化树结构

class MyTree
{
public:
    MyTree(DataNode *root);//目前只提供有参构造函数

    void add_node(DataNode* parent, DataNode *node); //增加子节点
    bool is_realy_contains_node(DataNode *node); //判断其是否含有某个节点
    void remove_node(DataNode *node);//删除某个节点
    void destroy_tree(DataNode* parent);//销毁树
    void ergodicTree(DataNode* root);//遍历树

private:
    DataNode *Root{nullptr};//保存根节点
};

具体实现函数

//demo使用QT编写,所以引入和使用了QT的数据类型
#include "mytree.h"
#include <QDebug>
#include <QQueue>

MyTree::MyTree(DataNode *root)
{
    Root = root;
}

//给指定的父节点增加子节点
void MyTree::add_node(DataNode *parent, DataNode *node)
{
    parent->m_child_list.append(node);
    node->m_parent = parent;
}
//判断节点是否存在树中,通过递归的形式,访问节点的父节点,直到其父节点为空时,判断此节点是否和Root相同,同则存在;
bool MyTree::is_realy_contains_node(DataNode *node)
{
    if(node->m_parent == NULL)
    {
        if(node == Root)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    bool val = is_realy_contains_node(node->m_parent);
    return val;
}
//从树中删除指定节点
void MyTree::remove_node(DataNode *node)
{
	//首先调用上述函数,判定节点是否存在,不存在则不处理
    if(is_realy_contains_node(node))
    {
    	//这里要区别处理,当删除根节时,是不需要处理其子节点链表的
        if(node == Root)
        {
            destroy_tree(node);
        }
        else
        {
            destroy_tree(node);
            node->m_parent->m_child_list.removeOne(node);
        }
    }
}

//销毁树或某子树,递归执行
void MyTree::destroy_tree(DataNode *node)
{
	//传入节点为空,不执行
    if(!node)
    {
        return;
    }
    //当前节点的孩子节点链表为空时,delete
    if(node->m_child_list.isEmpty())
    {
        delete node;
        qDebug() << "delete "  + node->m_data << endl;
        return;
    }
    //遍历孩子节点链表,执行递归
    for(int i = 0; i< node->m_child_list.size(); i++)
    {
        destroy_tree(node->m_child_list.at(i));
    }
    node->m_child_list.clear(); //清空链表
    delete node;//delte根节点
    qDebug() << "delete "  + node->m_data << endl;
}
//遍历Tree,实现了先序、后续、层次遍历
void MyTree::ergodicTree(DataNode *root)
{
    //先序遍历
//    qDebug() << root->m_data <<endl;
//    if(root->m_child_list.isEmpty())
//    {
//        return;
//    }
//    for(int i=0; i < root->m_child_list.size(); i++)
//    {
//        ergodicTree(root->m_child_list.at(i));
//    }

    //后序遍历
//    if(root->m_child_list.isEmpty())
//    {
//        qDebug() << root->m_data <<endl;
//        return;
//    }
//    for(int i=0; i < root->m_child_list.size(); i++)
//    {
//        ergodicTree(root->m_child_list.at(i));
//    }
//    qDebug() << root->m_data <<endl;

    //层次遍历
    QQueue<DataNode*> Q;//缓存节点队列,访问的节点都追加进去
    Q.append(root);
    while (!Q.isEmpty()) {
        DataNode *node = Q.dequeue(); //弹出队列首节点
        qDebug() << node->m_data << endl;
        if(!node->m_child_list.isEmpty())
        {
            for(int i = 0; i < node->m_child_list.size(); i++)
            {
                Q.append(node->m_child_list.at(i));
            }
        }
    }

}
};

代码如下(示例):

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import  ssl
ssl._create_default_https_context = ssl._create_unverified_context

三、使用QT的TreeView进行验证

//数据结构形式
在这里插入图片描述

demo源码如下(示例):

//----------------————————————————————-——————————————————>源码

//----------------------------------------------------------------->tree.h
#ifndef MYTREE_H
#define MYTREE_H
#include <QString>
#include <QList>

class DataNode
{
public:
    DataNode *m_parent{nullptr};
    QString m_data;
    QList<DataNode*> m_child_list;
    DataNode(DataNode* parent, QString data) {m_parent = parent; m_data = data;}
    void init(DataNode* parent, QString data) {m_parent = parent; m_data = data;}
};

class MyTree
{
public:
    MyTree(DataNode *root);
    ~MyTree();

    void add_node(DataNode* parent, DataNode *node);
    bool is_realy_contains_node(DataNode *node);
    void remove_node(DataNode *node);
    void destroy_tree(DataNode* parent);
    void ergodicTree(DataNode* root);

private:
    DataNode *Root{nullptr};
};

#endif // MYTREE_H

//------------------------------------------------------------>tree.cpp

#include "mytree.h"
#include <QDebug>
#include <QQueue>

MyTree::MyTree(DataNode *root)
{
    Root = root;
}

MyTree::~MyTree()
{
    destroy_tree(Root);
}

void MyTree::add_node(DataNode *parent, DataNode *node)
{
    parent->m_child_list.append(node);
    node->m_parent = parent;
}

bool MyTree::is_realy_contains_node(DataNode *node)
{
    if(node->m_parent == NULL)
    {
        if(node == Root)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    bool val = is_realy_contains_node(node->m_parent);
    return val;
}

void MyTree::remove_node(DataNode *node)
{
    if(is_realy_contains_node(node))
    {
        if(node == Root)
        {
            destroy_tree(node);
        }
        else
        {
            destroy_tree(node);
            node->m_parent->m_child_list.removeOne(node);
        }
    }
}

void MyTree::destroy_tree(DataNode *node)
{
    if(!node)
    {
        return;
    }
    if(node->m_child_list.isEmpty())
    {
        delete node;
        qDebug() << "delete "  + node->m_data << endl;
        return;
    }
    for(int i = 0; i< node->m_child_list.size(); i++)
    {
        destroy_tree(node->m_child_list.at(i));
    }
    node->m_child_list.clear();
    delete node;
    qDebug() << "delete "  + node->m_data << endl;
}

void MyTree::ergodicTree(DataNode *root)
{
    //先序遍历
//    qDebug() << root->m_data <<endl;
//    if(root->m_child_list.isEmpty())
//    {
//        return;
//    }
//    for(int i=0; i < root->m_child_list.size(); i++)
//    {
//        ergodicTree(root->m_child_list.at(i));
//    }

    //后序遍历

//    if(root->m_child_list.isEmpty())
//    {
//        qDebug() << root->m_data <<endl;
//        return;
//    }

//    for(int i=0; i < root->m_child_list.size(); i++)
//    {
//        ergodicTree(root->m_child_list.at(i));
//    }
//    qDebug() << root->m_data <<endl;

    //层次遍历
    QQueue<DataNode*> Q;
    Q.append(root);
    while (!Q.isEmpty())
     {
        DataNode *node = Q.dequeue();
        qDebug() << node->m_data << endl;
        if(!node->m_child_list.isEmpty())
        {
            for(int i = 0; i < node->m_child_list.size(); i++)
            {
                Q.append(node->m_child_list.at(i));
            }
        }
    }
}

//------------------------------------------------------------>mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QStandardItemModel>

//前置声明
class DataNode;

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    void treeView_init(DataNode *root);

private:
    Ui::MainWindow *ui;
    QStandardItemModel *model{nullptr};

};
#endif // MAINWINDOW_H

//------------------------------------------------------------>mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mytree.h"
#include <QDebug>
#include <QQueue>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //创建treeview model
    model = new QStandardItemModel(ui->treeView);
    ui->treeView->setModel(model);

    //初始化树
    DataNode *Root = new DataNode(NULL, "Root");
    MyTree tree(Root);

    DataNode *data1_1 = new DataNode(Root, "data1_1");
    DataNode *data1_2= new DataNode(Root, "data1_2");
    DataNode *data1_3 = new DataNode(Root, "data1_3");

    DataNode *data2_1 = new DataNode(Root, "data2_1");
    DataNode *data2_2 = new DataNode(Root, "data2_2");
    DataNode *data2_3 = new DataNode(Root, "data2_3");

    DataNode *data3_1 = new DataNode(Root, "data3_1");
    DataNode *data3_2 = new DataNode(Root, "data3_2");
    DataNode *data3_3 = new DataNode(Root, "data3_3");

    tree.add_node(Root, data1_1);
    tree.add_node(Root, data1_2);
    tree.add_node(Root, data1_3);

    tree.add_node(data1_2, data2_1);
    tree.add_node(data1_2, data2_2);
    tree.add_node(data1_2, data2_3);

    tree.add_node(data2_2, data3_1);
    tree.add_node(data2_2, data3_2);
    tree.add_node(data2_2, data3_3);

    //根据Tree,初始化TreeView
    treeView_init(Root);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::treeView_init(DataNode *root)
{
	//清空model
	model->clear();
	//以层次遍历的方式进行Tree View的创建
    QQueue<DataNode*> Q;//节点队列
    Q.append(root);
    QQueue<QStandardItem*> QS;//QStandModel队列
    QStandardItem *item_Root = new QStandardItem();
    model->appendRow(item_Root);
    QS.append(item_Root);

    while (!Q.isEmpty()) {
        DataNode *node = Q.dequeue();
        QStandardItem *item_root = QS.dequeue();
        if(!node->m_child_list.isEmpty())
        {
            for(int i = 0; i < node->m_child_list.size(); i++)
            {
                qDebug() << node->m_child_list.at(i)->m_data << endl;
                QStandardItem *item = new QStandardItem(node->m_child_list.at(i)->m_data);
                item_root->appendRow(item);
                QS.append(item);
                Q.append(node->m_child_list.at(i));
            }
        }
    }
}

实现效果如下—》
在这里插入图片描述


总结

一步步进行多叉树的创建、节点增加、节点删除、输的销毁,一步步的实现过程中,增加了对递归、迭代算法的理解,后续可能进一步增加功能,目前浅浅记录一下。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值