R G B element array swap

前端 未结 3 1500
深忆病人
深忆病人 2021-01-17 04:16

I\'m trying to create this c++ program to perform the description below. I am pretty certain the issue is in the recursive, but uncertain how to fix it. I\'m guessing it j

3条回答
  •  执笔经年
    2021-01-17 04:19

    There are many issues with your code.

    1) You call the function RGBorder with a character pointer, and then attempt to get the number of characters using this:

    size_t sz = sizeof(c_a)/sizeof(*c_a);
    

    This will not get you the number of characters. Instead this will simply get you the

    sizeof(char *) / sizeof(char)
    

    which is usually 4 or 8. The only way to call your function using a char array is either provide a null-terminated array (thus you can use strlen), or you have to pass the number of characters in the array as a separate argument:

    char *RGBorder(char *c_a, int size)
    

    2) I didn't go through your code, but there are easier ways to do a 3-way partition in an array. One popular algorithm to do this is one based on the Dutch National Flag problem.

    Since you want the array in RGB order, you know that the series of G will always come in the middle (somewhere) of the sequence, with R on the left of the sequence, and B always on the right of the sequence.

    So the goal is to simply swap R to the left of the middle, and B to the right of the middle. So basically you want a loop that incrementally changes the "middle" when needed, while swapping R's and B's to their appropriate position when they're detected.

    The following code illustrates this:

    #include 
    
    char *RGBorder(char *c_a, int num)
    {
        int middle = 0;  // assume we only want the middle element
        int low = 0;     // before the G's
        int high = num - 1;  // after the G's
    
        while (middle <= high)
        {
            if ( c_a[middle] == 'R' )  // if we see an 'R' in the middle, it needs to go before the middle
            {
                std::swap(c_a[middle], c_a[low]);  // swap it to a place before middle
                ++middle;  // middle has creeped up one spot
                ++low;     // so has the point where we will swap when we do this again
            }
            else
            if (c_a[middle] == 'B')  // if we see a 'B' as the middle element, it needs to go after the middle
            {
                std::swap(c_a[middle], c_a[high]); // place it as far back as you can
                --high;  // decrease the back position for next swap that comes here
            }
            else
               ++middle;  // it is a 'G', do nothing
        }
        return c_a;
    }
    

    Live Example


    Here is another solution that uses std::partition.

    #include 
    #include 
    
    char *RGBorder(char *c_a, int num)
    {
        auto iter = std::partition(c_a, c_a + num, [](char ch) {return ch == 'R';});
        std::partition(iter, c_a + num, [](char ch) {return ch == 'G';});
        return c_a;
    }
    

    Live Example

    Basically, the first call to std::partition places the R's to the front of the array. Since std::partition returns an iterator (in this case, a char *) to the end of where the partition occurs, we use that as a starting position in the second call to std::partition, where we partition the G values.

    Note that std::partition also accomplishes its goal by swapping.


    Given this solution, we can generalize this for an n-way partition by using a loop. Assume we want to place things in RGBA order (4 values instead of 3).

    #include 
    #include 
    #include 
    
    char *RGBorder(char *c_a, int num, char *order, int num2)
    {
        auto iter = c_a;
        for (int i = 0; i < num2 - 1; ++i)
            iter = std::partition(iter, c_a + num, [&](char ch) {return ch == order[i];});
        return c_a;
    }
    
    
    int main()
    {
        char ca[] = "AGBRRBARGGARRBGAGRARAA";
        std::cout << RGBorder(ca, strlen(ca), "RGBA", 4);
    }
    

    Output:

    RRRRRRRGGGGGBBBAAAAAAA
    

提交回复
热议问题