递归优化

时间:2013-07-23 09:31:31

标签: c++ recursion

我目前正在研究一种算法,在某些时候我必须经历一个图像并对具有相同属性的像素进行分组。我从最左上角的像素开始,我使用递归:从输入像素我可以获得邻近像素的高度,如果第一个具有相同的属性,那么我通过将此像素作为输入像素调用相同的函数。

以下是一些代码(请记住,这仍在进行中)。 基本呼叫者:

// R.A.G.
for( std::vector<Cell*>::iterator iterCell = cellVec.begin();
     iterCell != cellVec.end(); ++iterCell )
{
    Cell* mother = (*iterCell);

    if( mother->visited != true )
    {
        mother->visited = true;
    }
    CheckNeighbors( mother );
}

递归函数:

void
CheckNeighbors( Cell* mother )
{
    Cell* cell = nullptr;

    // Get the neighbours for the cell.
    //  5   6   7
    //  4   c   0
    //  3   2   1
    if( (cell=CheckCell( 1, 0, mother )) != mother )
    {
        mother = cell;
        CheckNeighbors( mother );
    }
    if( (cell=CheckCell( 1, 1, mother )) != mother )
    {
        mother = cell;
        CheckNeighbors( mother );
    }
    if( (cell=CheckCell( 0, 1, mother )) != mother )
    {
        mother = cell;
        CheckNeighbors( mother );
    }
    if( (cell=CheckCell( -1, 1, mother )) != mother )
    {
        mother = cell;
        CheckNeighbors( mother );
    }
    if( (cell=CheckCell( -1, 0, mother )) != mother )
    {
        mother = cell;
        CheckNeighbors( mother );
    }
    if( (cell=CheckCell( -1, -1, mother )) != mother )
    {
        mother = cell;
        CheckNeighbors( mother );
    }
    if( (cell=CheckCell( 0, -1, mother )) != mother )
    {
        mother = cell;
        CheckNeighbors( mother );
    }
    if( (cell=CheckCell( 1, -1, mother )) != mother )
    {
        mother = cell;
        CheckNeighbors( mother );
    }
}

我如何检查细胞:

Cell*
CheckCell( int x, int y, Cell* cell )
{
    // Here a cell is one pixel, but it depends on the size of the window we choose.
    // So for an image of 640*480, windowSize = 1, w = 640, h = 480
    x += cell->window.x()/windowSize;
    y += cell->window.y()/windowSize;

    // The cell at (x, y) coordinates is not in the map
    if( x < 0 || x >= w || y < 0 || y >= h ) return cell;

    // Get the neighbor cell in (x, y)
    // NB: cellVec has been filled up earlier and contains all the cells
    Cell* neighbor = cellVec.at( (y*w) + x );

    // The neighbor cell has already been visited
    if( neighbor->visited ) return cell;

    // The neighbor cell is of the same class as the mother cell
    if( neighbor->cClass != cell->cClass ) return cell;

    // Set the region number for the neighbor
    neighbor->visited = true;

    return neighbor;
}

所以这是我的问题:我确信这可以改善,但我想知道如何。 我应该使用其他递归的东西吗? 如何改进这种递归? 我读了关于尾调用优化的this article,但由于我无法丢弃调用者的状态,因此无法应用。但是我还有其他技巧吗?

感谢您的回答,我希望我已经足够明确了。

注意:如果我的图像是单色的,大小为640 * 480,单元格大小为2 * 2像素,我有153765个调用。当然还有1 * 1单元大小的段错误。我知道我可以增加堆栈的大小,但我更愿意找到另一种解决方案。

2 个答案:

答案 0 :(得分:2)

您正在做的是Flood fill,实施为Depth First Search

要改进它,你可以:

  • 将其重新命名为Breadth First Search
  • 使用堆栈实施深度优先搜索。这仍然是一个相同的想法,但使用堆栈而不是递归应该使您的代码更快,并使用更少的内存。

答案 1 :(得分:1)

使用迭代方法会更快,因为您已经读取了向量中的所有元素,并且可以线性地运行它。这是更加缓存友好的,你摆脱了所有抵消的东西

// Copy all elements starting from the selected cell pointed to by the iterator, if 
// they are equal to the cell
void checkAllCells(vector<Cell*> input, vector<Cell*>::iterator it; vector<Cell*> output)
{
    auto localIt = it;
    while( localIt != input.end())
    {
        if ((*localIt)->class == (*it)->class)
        {
            output.pushback(*it);
        }
    }
}

请注意,您不需要像visited等那样进行簿记,因为从第一个元素开始,您将找到所有其他相同的元素。如果你接着第二个元素,你知道,你已经在考虑前面的元素了