提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
经常使用得都是二叉树,今天记录一下多叉树的基本实现步骤,其他的后续慢慢增加。
一、初始化节点结构体
//这里因为想尝试新的方式,没有使用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));
}
}
}
}
实现效果如下—》
总结
一步步进行多叉树的创建、节点增加、节点删除、输的销毁,一步步的实现过程中,增加了对递归、迭代算法的理解,后续可能进一步增加功能,目前浅浅记录一下。