在DFS实现中使用程序堆栈

时间:2013-11-12 11:32:48

标签: c stack

我的代码中有一个标准的DFS实现,它在每次调用时使用动态分配的堆栈。

我称这个功能很多。通常仅在小规模(200-1000)个节点上运行,但有时会有一个大型连接组件,其节点数量超过一百万个。

分析器显示在分配堆栈时浪费了大量的计算时间。我想尝试重用现有的内存(例如调用堆栈)。但是,该功能必须保持线程安全。

是否有一种有效的方法可以动态使用调用堆栈而不会使函数递归?

到目前为止,我最好的想法是使用额外的参数使函数递归,该参数在每次后续调用时使自动堆栈大小加倍。

伪C:

void dfs(size_t stack_length, void * graph, graphnode_t start_node) {
    graphnode_t stack[stack_length];
    size_t stack_size = 0;

    for (all nodes) {
        // do something useful
        if (stack_size < stack_length) {
            stack[stack_size++] = new_node;
        } else {
            dfs(stack_length * 2, graph, new_node);
        }
    }

}

1 个答案:

答案 0 :(得分:0)

听起来你正在描述你的算法只用一个graphnode_t数组就可以正常运行(尽管你称之为堆栈,我认为这不适用于此),唯一真正的问题是你不确定开始时应该有多大。

如果是这种情况,我建议首先不要让这个(可能很大的)数组成为局部变量,因为这会导致实际程序堆栈出现问题。而是让它成为一个静态指针,指向动态大小的内存,如果需要,你可以定期扩展。

ensure_size(graphnode_t **not_a_stack_ptr, unsigned long *length_ptr)
{
    if (!*not_a_stack_ptr)
    {
        *not_a_stack_ptr = malloc(sizeof(graphnode_t) * MINIMUM_ENTRY_COUNT);
        *length_ptr = MINIMUM_ENTRY_COUNT;
    }
    else if (size needs to double)
    {
        *length_ptr *= 2;
        *not_a_stack_ptr = realloc(*not_a_stack_ptr, sizeof(graphnode_t) * (*length_ptr));
    }
}


struct thread_arguments {
    void * graph;
    graphnode_t start_node;
}

dfs_thread(void *void_thread_args)
{
    struct thread_arguments *thread_args = void_thread_args;
    graphnode_t *not_a_stack = NULL;
    unsigned long not_a_stack_length = 0;

    for (all nodes)
    {
        ensure_size(&not_a_stack, &not_a_stack_length);
        stack[stack_size++] = new_node;
    }

    if (not_a_stack) free(not_a_stack);
}

注意:您的伪代码表明可以根据您拥有的节点数确定最大大小。通过使用它来预先执行一个完整大小的malloc,您将获得最大的性能提升。