简体   繁体   中英

Why is one method slower than the other one

I have these two variants of my code which one of them runs significantly slower then the other one, although I think it should not do it. Could somebody please explain me what takes it so long to run while doing it like this? The code is a basic floodfill algorithm, the pos variable is declared previously as unsigned long Thank you

This piece of code runs much slower than the second one.

void
flood(byte * array, unsigned long x, unsigned long y, byte value)
{
    node_t *head = NULL;

    queue(&head, x, y);
    while (head != NULL) {
        unsigned long *ret = dequeue(&head);

        pos = ret[0] + ret[1] * pgmWidth;
        if (pos >= 0 && pos < pgmSize && ret[1] < pgmHeight &&
            array[pos] == UCHAR_MAX) {
            array[pos] = value;

            queue(&head, ret[0] + 1, ret[1]);
            queue(&head, ret[0], ret[1] + 1);
            queue(&head, ret[0], ret[1] - 1);
            queue(&head, ret[0] - 1, ret[1]);
        }
        free(ret);
    }
}

This piece runs much faster although there is more conditions then in the first one

void
flood(byte * array, unsigned long x, unsigned long y, byte value)
{
    node_t *head = NULL;

    queue(&head, x, y);
    while (head != NULL) {
        unsigned long *ret = dequeue(&head);

        pos = ret[0] + ret[1] * pgmWidth;
        if (ret[0] >= 0 && ret[0] < pgmWidth && ret[1] >= 0 &&
            ret[1] < pgmHeight && array[pos] == UCHAR_MAX) {
            array[pos] = value;

            queue(&head, ret[0] + 1, ret[1]);
            queue(&head, ret[0], ret[1] + 1);
            queue(&head, ret[0], ret[1] - 1);
            queue(&head, ret[0] - 1, ret[1]);
        }
        free(ret);
    }
}

The is a significant difference between the 2 functions: the second piece of code stops the flood at the left and right edges of the 2D array whereas the first does not.

The set of pixels that are explored is different: for example imagine the array is filled with UCHAR_MAX values except for a vertical line running from top to bottom. The first code will flood the array on both sides from any pixel not on the vertical line whereas the second will only flood half of the surface.

This possibly explains the difference in running times, depending on the actual contents of the array at the call.

Both approaches may make sense, but have different semantics:

  • the first code floods the array as the surface of a cylinder with a one pixel misalignment along the junction.
  • the second code floods the array as a flat rectangle, which seems more consistent.

There are ways to further improve the code:

  • you should remove 2 redundant tests as the coordinates are unsigned, which are defined to have wrap around semantics,
  • you should only queue pixels that are actually reached,
  • you should change the pixel value before queueing the pixel coordinates to avoid queueing the same pixel multiple times.
void flood(byte *array, unsigned long x, unsigned long y, byte value)
{
    node_t *head = NULL;

    pos = x + y * pgmWidth;
    if (x < pgmWidth && y < pgmHeight && array[pos] == UCHAR_MAX) {
        array[pos] = value;
        queue(&head, x, y);
    }

    while (head != NULL) {
        unsigned long *ret = dequeue(&head);
        x = ret[0];
        y = ret[1];
        free(ret);

        pos = x + y * pgmWidth;
        
        if (x + 1 < pgmWidth && array[pos + 1] == UCHAR_MAX) {
            array[pos + 1] = value;
            queue(&head, x + 1, y);
        }
        if (y + 1 < pgmHeight && array[pos + pgmWidth] == UCHAR_MAX) {
            array[pos + pgmWidth] = value;
            queue(&head, x, y + 1);
        }
        if (y > 0 && array[pos - pgmWidth] == UCHAR_MAX) {
            array[pos - pgmWidth] = value;
            queue(&head, x, y - 1);
        }
        if (x > 0 && array[pos - 1] == UCHAR_MAX) {
            array[pos - 1] = value;
            queue(&head, x - 1, y);
        }
    }
}

Finally, using global variables for pos , pgmWidth and pgmHeight makes the code slower. There is no real value in using a global variable for pos anyway. Try this alternative:

void flood(byte *array, unsigned long x, unsigned long y, byte value)
{
    node_t *head = NULL;
    unsigned long width = pgmWidth;
    unsigned long height = pgmHeight;
    unsigned long pos;

    p = x + y * width;
    if (x < width && y < height && array[pos] == UCHAR_MAX) {
        array[pos] = value;
        queue(&head, x, y);
    }

    while (head != NULL) {
        unsigned long *ret = dequeue(&head);
        x = ret[0];
        y = ret[1];
        free(ret);

        pos = x + y * width;
        
        if (x + 1 < width && array[pos + 1] == UCHAR_MAX) {
            array[pos + 1] = value;
            queue(&head, x + 1, y);
        }
        if (y + 1 < height && array[pos + width] == UCHAR_MAX) {
            array[pos + width] = value;
            queue(&head, x, y + 1);
        }
        if (y > 0 && array[pos - width] == UCHAR_MAX) {
            array[pos - width] = value;
            queue(&head, x, y - 1);
        }
        if (x > 0 && array[pos - 1] == UCHAR_MAX) {
            array[pos - 1] = value;
            queue(&head, x - 1, y);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM