R G B元素数组交换

时间:2018-08-18 01:47:50

标签: c++ arrays compare-and-swap

我正在尝试创建此c ++程序以执行以下描述。我非常确定问题在于递归,但不确定如何解决。我猜想它只会不断迭代到无穷大并崩溃。我什至没有输出。我以为我可以比较以前的指针和当前的指针,并根据词典顺序执行一个三段式的临时交换。我将使用一个指针来遍历数组,并在每次交换后将其递减,然后以该ptr作为参数进行递归调用。没有工作,我在这里,请帮我:)。如果有一个更简单的解决方案也可以使用,但更希望了解我在这段代码中出了错。

#include <string>
#include <iostream>
using namespace std;

// Given an array of strictly the characters 'R', 'G', and
// 'B', segregate the values of the array so that all the
// Rs come first, the Gs come second, and the Bs come last.
// You can only swap elements of the array.

char* RGBorder(char* c_a)
{

    size_t sz = sizeof(c_a)/sizeof(*c_a);
    char* ptr_ca = c_a;
    char* prv_ptr = ptr_ca;
    ptr_ca++;
    char temp;

    while(*ptr_ca)
    {
        switch(*ptr_ca)
        {
            case 'R' :
                if( *prv_ptr < *ptr_ca ) {
                    temp = *prv_ptr; *prv_ptr = *ptr_ca; *ptr_ca = temp;
                } else if( *prv_ptr == *ptr_ca ) {
                    continue;
                } else { ptr_ca--; RGBorder(ptr_ca); }

            case 'G' :
                if( *prv_ptr < *ptr_ca ) {
                    temp = *prv_ptr; *prv_ptr = *ptr_ca; *ptr_ca = temp;
                } else if( *prv_ptr == *ptr_ca ) {
                    continue;
                } else { ptr_ca--; RGBorder(ptr_ca); }
            default:
                ptr_ca++;
                continue;
        }
        ptr_ca++;
        cout << *ptr_ca;
    }

    return c_a;
}

int main()
{
    char ca[] =  {'G', 'B', 'R', 'R', 'B', 'R', 'G'};
    char *oca =RGBorder(ca);
    char *pca = oca;
    while(*pca)
    {
        cout << *pca << endl;
        pca++;
    }
}

3 个答案:

答案 0 :(得分:2)

很抱歉,不过,这段代码是一团糟。我并不是说那些错误,对于初学者来说,这些错误是可以原谅的。我的意思是格式化。一行中的多个语句使读取和调试代码变得异常困难。简短的变量名没有立即的内在含义,这使得很难理解代码应该做什么。 using namespace std;也是非常不好的做法,但是我可以想象,只要那门课程的授课者都教过您这样做。

第一个问题

您的casebreak,因此您对R执行所有情况,对G执行defaultG 。同样,您的代码将永远不会到达循环的最后两行,因为在每种情况下您都continue之前都退出了。

第二个问题

您有无尽的循环。在这两个case中,您有两种情况会陷入无限循环:

  1. else if( *prv_ptr == *ptr_ca )分支中,您只需continue;,而无需更改指针。

  2. else分支中,您执行ptr_ca--;,然后在default中再次调用ptr_ca++;
    (请注意,即使使用{{ 1}} s,您仍会在循环结束时调用break。)

在这两种情况下,指针都不会改变,因此一旦遇到任何一种情况,循环就永远不会退出。

第三个可能的问题

我只能猜测,因为从名称中看不出来,但是看来ptr_ca++;应该保存循环中最后一个指针是什么?如果是这样,永远不更新该指针似乎是错误的。无论哪种方式,适当的变量名都会使该指针的目的更加清楚。 (附带说明,prv_ptr的一致用法可以帮助识别此类问题。如果您拥有的变量不是const,但从未更新过,则您要么忘记添加const,要么忘了更新。)

如何修复

设置代码格式:

  • 请勿使用const
  • 每行一条语句。
  • 为变量指定专有名称,以便轻松识别出什么。 (这不是1993年,实际上,我宁愿有一个using namespace std;而不是thisIsThePointerHoldingTheCharacterThatDoesTheThing。)

解决上述问题(添加ptr_xy,请确保您的循环确实退出了)。

然后调试您的代码。用调试器。运行时。使用断点并逐行浏览,在代码执行时检查指针的值。花哨的东西。

祝你好运!

答案 1 :(得分:2)

您的代码有很多问题。

1)您使用字符指针调用函数RGBorder,然后尝试使用以下方法获取字符数:

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

这不会让您获得字符数。相反,这只会使您获得

sizeof(char *) / sizeof(char)

通常为4或8。使用char数组调用函数的唯一方法是提供一个以空值结尾的数组(因此您可以使用strlen),或者必须传递字符数在数组中作为单独的参数:

char *RGBorder(char *c_a, int size)

2)我没有遍历您的代码,但是有更简单的方法可以在数组中进行三向分区。一种流行的算法是基于Dutch National Flag问题的算法。

由于您希望按RGB的顺序排列数组,因此您知道G的序列将始终位于序列的中间(某处),R位于序列的左侧序列,B始终在序列的右侧。

因此,目标是简单地将R交换到中间的左侧,并将B交换到中间的右侧。因此,基本上,您需要一个循环,在需要时逐步更改“中间”,同时在检测到R和B时将其交换到适当位置。

以下代码对此进行了说明:

#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


这是使用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

基本上,对std::partition的第一次调用将R放置在数组的前面。由于std::partition返回一个迭代器(在这种情况下为char *)到发生分区的末尾,因此我们将其用作对std::partition的第二次调用的起始位置对G值进行分区。

请注意,std::partition也通过交换来实现其目标。


鉴于此解决方案,我们可以使用循环将其推广到n路分区。假设我们要按RGBA顺序放置事物(4个值而不是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);
}

输出:

RRRRRRRGGGGGBBBAAAAAAA

答案 2 :(得分:0)

只需计算“ R”,“ G”和“ B”字母的数量,然后从头开始填充数组即可。 简单得多,没有递归。