Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/134.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 什么';构建非循环依赖关系的最简单、最有效的数据结构是什么?_C++_Algorithm_Data Structures_Dependencies_Graph Theory - Fatal编程技术网

C++ 什么';构建非循环依赖关系的最简单、最有效的数据结构是什么?

C++ 什么';构建非循环依赖关系的最简单、最有效的数据结构是什么?,c++,algorithm,data-structures,dependencies,graph-theory,C++,Algorithm,Data Structures,Dependencies,Graph Theory,我试图建立一个序列来决定销毁对象的顺序。我们可以假设没有周期。如果对象A在其(A)构造期间使用对象B,则对象B在对象A的销毁期间仍应可用。因此,所需的销毁顺序为A,B。如果另一个对象C在其(C)构造期间也使用对象B,则所需的顺序为A,C,B。一般而言,只要对象X仅在构造期间使用该对象的所有其他对象之后销毁,则销毁是安全的 如果到目前为止我们的销毁顺序是AECDBF,我们现在得到了一个X(我们从来都不知道最初的构造顺序,它是动态发现的),它在构造过程中使用C和F,那么我们可以通过将X放在列表中当前

我试图建立一个序列来决定销毁对象的顺序。我们可以假设没有周期。如果对象A在其(A)构造期间使用对象B,则对象B在对象A的销毁期间仍应可用。因此,所需的销毁顺序为A,B。如果另一个对象C在其(C)构造期间也使用对象B,则所需的顺序为A,C,B。一般而言,只要对象X仅在构造期间使用该对象的所有其他对象之后销毁,则销毁是安全的

如果到目前为止我们的销毁顺序是AECDBF,我们现在得到了一个X(我们从来都不知道最初的构造顺序,它是动态发现的),它在构造过程中使用C和F,那么我们可以通过将X放在列表中当前较早的C或F(恰好是C)之前来获得一个新的安全顺序。因此,新的顺序将是ABXCDEF

在X示例的上下文中,链表似乎不合适,因为需要进行大量线性扫描来确定哪个是较早的,C还是F。数组将意味着插入速度较慢,这将是更常见的操作之一。优先级队列实际上没有合适的接口,没有“在这些项中最早的一项之前插入此项”(我们手头不知道正确的优先级,以确保它在较低优先级元素之前插入,并且不会干扰其他项)

所有对象都被构造,所需的顺序被计算,序列将被迭代一次并按顺序销毁。不需要执行其他操作(事实上,在使用任何数据结构来确定顺序之后,都可以将其复制到平面阵列中并丢弃)

编辑:只是澄清一下,第一次使用对象是在构建对象时。所以如果A使用B,那么E使用B,当E尝试使用B时,它已经被创建了。这意味着堆栈不会给出所需的顺序。当我们需要AEB时,AB将成为ABE

Edit2:我正在尝试建立“随走随走”的顺序,以保持算法的正确性。我宁愿避免建立一个大型中间结构,然后将其转换为最终结构


编辑3:我把这件事弄得太复杂了;p

由于依赖项总是在依赖于它们的对象之前进行初始化,并且在销毁这些对象之前一直可用,所以按照与初始化完全相反的顺序销毁对象应该总是安全的。因此,您所需要的只是一个链表,在初始化对象和销毁时,您可以将它们预先添加到该链表中,并且每个对象都可以请求初始化其在初始化自身之前尚未初始化的所有依赖项

因此,对于每个对象的初始化:

  • 初始化self,同时初始化未初始化的依赖项
  • 将self添加到销毁列表的前面(如果使用堆栈,则将self推到堆栈上)

对于销毁,只需从前面向前移动链接列表(或将项目从堆栈中弹出,直到为空),即可在执行时销毁。因此,您第一段中以B、A、C顺序草签的示例将以C、A、B顺序销毁,这是安全的;编辑中的示例将按顺序B、A、E初始化(而不是A、B、E,因为A依赖于B),然后按顺序E、A、B销毁,这也是安全的。

听起来您应该尝试按照您描述的模式构建一个有向无环图。邻接列表表示法(可能是链表的向量,因为您正在动态地获得新节点)应该可以做到这一点


有一件事我不太清楚:你是需要在随机时间进行计算,还是在你得到所有信息之后?我假设是后者,你可以等到你的图表完成。如果是这样的话,你的问题就是a,在边和顶点的实现中,时间是线性的。这是一个相对简单的算法。你的描述让我有点头晕目眩(抱歉,吃午饭让我又慢又困),但实际上你可能需要一个“反向”拓扑排序,但原则是相同的。我不会试图解释算法是如何工作的(请参阅:slow and sleepy),但我认为应用程序应该是清晰的。除非我完全错了,在这种情况下,没关系

总结如下: 从某种意义上说,您正在构建数据结构,一个图形,所需的时间与您希望的一样快(这取决于插入的方式)。该图反映了哪些对象需要等待哪些其他对象。然后,构建完成后,运行拓扑排序,这反映了它们的依赖关系


编辑:我已经有一段时间没有把“你的”和“你是”混在一起了(

这样表示:如果a的析构函数必须在B之后运行,则图的边从a到B。插入X意味着添加两条边,如果保留节点的排序索引,则这就是O(n log n))。要读取销毁顺序:拾取任意节点,请沿着边进行操作,直到无法再执行为止。可以安全地调用该节点的析构函数。然后选择剩余的一个节点(例如,您穿过的上一个节点)并重试


从您所说的情况来看,插入经常发生,但为了销毁,该序列只迭代一次:这种数据结构应该是合适的,因为它具有快速插入,而代价是查找速度较慢。也许其他人可以建议一种更快的方法来在这个数据结构中进行查找。

这听起来像是在用树叶建造一棵树

将其存储为一棵树

  • 每个资源都有一个节点
  • 让每个资源保留一个指向依赖于该资源的资源的指针的链接列表
  • 让每个资源记录它所依赖的资源数量
  • 保留一个顶级链接列表,其中列出了并没有
    typedef struct _dependent Dependent;
    typedef struct _resource_info ResourceInfo;
    
    struct _dependent 
    {
      Dependent * next;
      ResourceInfo * rinfo;
    }
    struct _resource_info
    {
      Resource * resource; // whatever user-defined type you're using
      size_t num_dependencies;
      Dependent * dependents;
    }
    
    //...
    Resource ** generateOrdering( size_t const numResources, Dependent * freeableResources )
    {
      Resource ** const ordering = malloc(numResources * sizeof(Resource *));
      Resource ** nextInOrder = ordering;
    
      if (ordering == NULL) return NULL;
      while (freeableResources != NULL)
      {
        Dependent * const current = freeableResources;
        Dependent * dependents = current->rinfo->dependents;
    
        // pop from the top of the list
        freeableResources = freeableResources->next;
    
        // record this as next in order
        *nextInOrder = current->rinfo->resource;
        nextInOrder++;
        free(current->rinfo);
        free(current);
    
        while (dependents != NULL)
        {
           Dependent * const later = dependents;
    
           // pop this from the list
           dependents = later->next;
    
           later->rinfo->num_dependencies--;
           if (later->rinfo->num_dependencies == 0)
           {
              // make eligible for freeing
              later->next = freeableResources;
              freeableResources = later;
           }
           else
           {
               free(later);
           }
        }
      }
      return ordering;
    }