R G B element array swap

前端 未结 3 1499
深忆病人
深忆病人 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 <algorithm>
    
    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 <algorithm>
    #include <iostream>
    
    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 <algorithm>
    #include <iostream>
    #include <cstring>
    
    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
    
    0 讨论(0)
  • 2021-01-17 04:22

    Sorry to put it blunt, but that code is a mess. And I don't mean the mistakes, those are forgivable for beginners. I mean the formatting. Multiple statements in one line make it super hard to read and debug the code. Short variable names that carry no immediate intrinsic meaning make it hard to understand what the code is supposed to do. using namespace std; is very bad practise as well, but I can imagine you were taught to do this by whoever gives that course.

    1st problem

    Your cases don't break, thus you execute all cases for R, and both G and default for G. Also your code will never reach the last 2 lines of your loop, as you continue out before in every case.

    2nd problem

    You have an endless loop. In both cases you have two situations where you'll end up in an endless loop:

    1. In the else if( *prv_ptr == *ptr_ca ) branch you simply continue; without changing the pointer.

    2. In the else branch you do ptr_ca--;, but then in default you call ptr_ca++; again.
      (Note that even with breaks you would still call ptr_ca++; at the end of the loop.)

    In both cases the pointer doesn't change, so once you end up in any of those conditions your loop will never exit.

    Possible 3rd problem

    I can only guess, because it is not apparent from the name, but it seems that prv_ptr is supposed to hold whatever was the last pointer in the loop? If so, it seems wrong that you don't update that pointer, ever. Either way, proper variable names would've made it more clear what the purpose of this pointer is exactly. (On a side note, consistent usage of const can help identify such issues. If you have a variable that is not const, but never gets updated, you either forgot to add const or forgot to update it.)

    How to fix

    Format your code:

    • Don't use using namespace std;.
    • One statement per line.
    • Give your variables proper names, so it's easy to identify what is what. (This is not 1993, really, I'd rather have a thisIsThePointerHoldingTheCharacterThatDoesTheThing than ptr_xy.)

    Fix the aforementioned issues (add breaks, make sure your loop actually exits).

    Then debug your code. With a debugger. While it runs. With breakpoints and stepping through line by line, inspecting the values of your pointers as the code executes. Fancy stuff.

    Good luck!

    0 讨论(0)
  • 2021-01-17 04:25

    just count the number of 'R', 'G' and 'B' letters and fill the array from scratch. much easier, no recursions.

    0 讨论(0)
提交回复
热议问题