如何使用 std::map 在C++中构建树结构

how to build a tree structure in C++ using std::map

本文关键字:构建 结构 C++ 何使用 std map      更新时间:2023-10-16

我正在尝试用C++编写一种树状结构。就像每棵树一样,有树枝和叶子。分支可以包含其他分支以及叶子。现在我的实现要求每个分支和叶子具有不同的功能。举个例子。取树结构

                                          Root                                             
                                |                          |                             
                             Branch1                     Branch2                     Branch3
      |                |                |
    Leaf1            Leaf2           Branch4

现在每个叶子和分支都有一个不同的函数要执行,所以叶子1将有一个名为leaf1_func的函数,叶子2将有leaf2_func,分支4有Branch4_func。

我最初试图实现复合设计模式。但这意味着我将拥有与叶子一样多的类。但是由于我有大量的叶子和树枝,我想避免创建更多的类。我意识到这是一个不寻常的情况,但希望有人能在这方面帮助我。在不创建太多类的情况下实现此树的最佳方法是什么。

我也在使用地图 STL 容器来存储数据,我想使用这个树实现来解决 TSP 问题中的这个问题。

#include <cstdlib>
#include <iostream>
#include <map>
using namespace std;
int n=4;
int min=1, max=10;


struct graph
{
int nodes;//total no. of nodes or vertices namely cities
std::map<std::pair<int,int>, int> graphMap;//an object that links a pair of vertices   
};

void directed_Graph(graph);
void directed_Graph(graph G)
{
//int n = G->nodes; //city count
int i, j;
for(i = 0; i <= n-1; i++)
{
    for(j = 0; j <= n-1; j++)
    {
        if(i!=j)
        {
            G.graphMap[std::make_pair(i,j)] = (rand()%10)+1;
            //cout<<G.graphMap[std::make_pair(i,j)]<<"n";
        }
        else
        {
            G.graphMap[std::make_pair(i,j)] = 0;
        }
    }
}
}

int main(int argc, char** argv) 
{
graph g;
g.nodes = 4;
directed_Graph(g);
return 0;
}

具有相同签名的不同函数仍然具有相同的类型。即使函数完全不相关,您也可以使用树(类型擦除(void *存储随机数据,然后在到达叶节点后类型转换回已知的实际类型。

struct node {
    void (*fptr)(); // pointer to any function taking no args, no return
    void *data; // pointer to anything, need to cast before using
};
void f() { std::cout << "hello"; }
void g() { std::cout << "world"; }
node a = { f, f };
node b = { g, g };
a.fptr();
static_cast< void (*)() >( b.data )();

还可以将虚拟方法与继承一起使用,并将指针指向树中的基类类型。这取决于节点到底是什么。

这些都与它进入图表的事实无关。

从您的图表外观来看,您似乎想要一个节点可以有两个以上子节点的树。 如果是这种情况,那么 STL 容器将不适合您。 它们是自平衡的二叉树。

如果你对二叉树没问题,那么有几种方法可以做到这一点。 第一种是编写函数,然后将函数指针或函子存储在树中。

#include <set>
int foo( ) {
  return 5;
}
std::set< int (*)( ) > my_set;
my_set.insert( &foo );

这种方法的问题在于所有函数都必须具有相同的类型,即采用相同的参数并具有相同的返回类型。 更重要的是,虽然它们可以定义不同的行为,但它们不能保持状态,即你不能在函数指针中存储数据。

正如你提到的,第二个选项是编写类。 如果您需要改变节点的行为,那么最好的方法是定义一个接口并使用多态性。

#include <set>
#include <iostream>
struct base {
  virtual void print( ) const = 0;
};
struct derived1 : public base {
  void print( ) const { std::cout << "derived1" << std::endl; }
};
struct derived2 : public base {
  void print( ) const { std::cout << "derived2" << std::endl; }
};
std::set< base* > my_set;
my_set.insert( new derived1( ));
my_set.insert( new derived2( ));

没有说你是否需要强制某些行为是叶子,而其他行为是内部节点,或者是否需要以特定方式对节点进行排序,但如果你这样做,那么你可以通过创建自定义小于函数来实现这一点:

bool operator < ( base const * const b1, base const * const b2 ) {
  // Figure out which is less here.
}

同样,如果你需要的东西不是二叉树,那么你就不走运了。 无论如何,你都需要编写一些代码来实现存储在每个节点中的行为,无论是函数还是类。

如果你的树深度有限,这样描述它很方便:

typedef std::map<std::string, double> action_map_t;
typedef std::map<std::string, action_map_t> objid_map_t;
typedef std::map<std::string, objid_map_t> objtype_map_t;
/

/....等等这里是深度== 3

objtype_map_t m_mapTooltipDuration;
m_mapTooltipDuration[objtype][objid][action] = atof(duration.c_str());