【问题标题】:Recursive to Iterative Transformation递归到迭代转换
【发布时间】:2011-08-30 19:32:47
【问题描述】:

我一直在尝试将我的代码从递归函数重写为迭代函数。

关于从递归代码到迭代代码,我想我会问是否有任何一般性的事情需要考虑/技巧/指南等。

例如我不知道如何迭代下面的代码,主要是由于递归内部的循环进一步依赖并调用下一个递归。

struct entry
{
    uint8_t values[8];
    int32_t num_values;
    std::array<entry, 256>* next_table;

    void push_back(uint8_t value) {values[num_values++] = value;}
};

struct node
{
    node*               children; // +0 right, +1 left
    uint8_t             value;
    uint8_t             is_leaf;
};

void build_tables(node* root, std::array<std::array<entry, 8>, 255>& tables, int& table_count)
{
    int table_index = root->value; // root is always a non-leave, thus value is the current table index.

    for(int n = 0; n < 256; ++n)
    {
        auto current = root;

        // Recurse the the huffman tree bit by bit for this table entry
        for(int i = 0; i < 8; ++i)
        {
            current = current->children + ((n >> i) & 1); // Travel to the next node    current->children[0] is left child and current->children[1] is right child. If current is a leaf then current->childen[0/1] point to the root.
            if(current->is_leaf)
                tables[table_index][n].push_back(current->value);
        }

        if(!current->is_leaf)
        {
            if(current->value == 0) // For non-leaves, the "value" is the sub-table index for this particular non-leave node
            {
                current->value = table_count++;
                build_tables(current, tables, table_count);
            }

            tables[table_index][n].next_table = &tables[current->value];
        }
        else
            tables[table_index][n].next_table = &tables[0];
    }   
}

【问题讨论】:

  • 考虑这个问题:(可能重复?)stackoverflow.com/questions/1549943/…
  • 很好的链接!谢谢,之前找的时候没找到。我知道 std::stack 的做法。但是,我似乎有点困惑,因为我的递归中有一个循环,下一个递归依赖于这个循环,不知道如何处理?
  • 如果您对代码的作用提供了解释,我会鼓励我回答,我没有时间自己尝试弄清楚。编辑:递归内的循环将变成循环内的循环。
  • 我正在构建一个用于霍夫曼解码的表(谷歌:“高效霍夫曼解码”)。所以“节点”结构是一棵霍夫曼树,我希望从中生成解码表。
  • 这可能有助于展示node 结构是如何定义的。

标签: c++ recursion iteration transformation


【解决方案1】:

由于tablestable_count 总是引用相同的对象,您可以通过将tablestable_countbuild_tables 的参数列表中取出并将它们存储为临时结构,然后做这样的事情:

struct build_tables_struct
{
  build_tables_struct(std::array<std::array<entry, 8>, 255>& tables, int& table_count) :
    tables(tables), table_count(table_count) {}
  std::array<std::array<entry, 8>, 255>& tables;
  int& table_count;
  build_tables_worker(node* root) 
  {
     ...
     build_tables_worker(current); // instead of build_tables(current, tables, table_count);
     ...
  }
}

void build_tables(node* root, std::array<std::array<entry, 8>, 255>& tables, int& table_count)
{
  build_tables_struct(tables, table_count).build_tables_worker(root);
}

当然,这仅适用于您的编译器不够聪明,无法自行进行优化的情况。

否则,您可以使其成为非递归的唯一方法是自己管理堆栈。我怀疑这会比递归版本快得多。

说了这么多,我怀疑你的性能问题是递归。与您的函数所做的工作相比,我认为将三个引用参数推送到堆栈并调用一个函数并不是一个巨大的负担。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-26
    • 2017-03-05
    • 2016-06-29
    • 1970-01-01
    相关资源
    最近更新 更多