递归优化

Optimisation on recursion

本文关键字:优化 递归      更新时间:2023-10-16

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

这里有一些代码(请记住,这仍在进行中)。基本呼叫方:

// 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;
}

所以我的问题是:我确信这是可以改进的,但我想知道如何改进。我应该使用其他递归吗?如何改进这种递归?我读过这篇关于尾调用优化的文章,但在我的案例中,由于我不能丢弃调用者的状态,所以这是不适用的。但是,我还有别的把戏可以用吗?

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

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

您正在做的是整体填充,实现为深度优先搜索。

要改进它,您可以:

  • 将其记为广度优先搜索
  • 使用堆栈实现深度优先搜索。这仍然是相同的想法,但使用堆栈而不是递归应该会使代码更快,使用更少的内存

使用迭代方法会更快,因为你已经在一个向量中拥有了所有元素,并且可以线性地运行它。这对缓存更友好,并且可以消除所有偏移的东西

// 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等那样记账,因为从第一个元素开始,您会发现所有其他元素都是相等的。如果你取第二个元素,你知道,你已经在考虑前面的元素