R G B 元素数组交换

R G B element array swap

本文关键字:数组 交换 元素      更新时间:2023-10-16

我正在尝试创建这个c ++程序来执行下面的描述。 我很确定问题出在递归中,但不确定如何解决它。 我猜它只是不断迭代到无穷大并崩溃。 我什至没有得到输出。 我想我可以比较以前的和当前的指针,并根据词典编纂执行 3 件式临时交换。 我会使用指针遍历数组并在每次交换后递减它,然后以该 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++;
}
}

您的代码存在许多问题。

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

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

这不会为您提供字符数。 相反,这只会让你

sizeof(char *) / sizeof(char)

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

char *RGBorder(char *c_a, int size)

2)我没有浏览您的代码,但是有更简单的方法可以在数组中进行3向分区。 一种流行的算法是基于荷兰国旗问题的算法。

由于您希望数组按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;
}

现场示例


这是另一个使用 std::p artition 的解决方案。

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

现场示例

基本上,对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

很抱歉说得直白了,但那段代码一团糟。我不是说错误,这些对于初学者来说是可以原谅的。我的意思是格式。一行中的多个语句使得阅读和调试代码变得非常困难。没有直接内在含义的短变量名称使得很难理解代码应该做什么。using namespace std;也是非常糟糕的做法,但我可以想象你是由任何教授该课程的人教你这样做的。

第一个问题

你的case不会break,因此你执行R的所有情况,以及GGdefault。此外,您的代码永远不会到达循环的最后 2 行,正如您之前在每种情况下continue的那样。

第二个问题

你有一个无限循环。在这两种case中,您都有两种情况,最终会陷入无限循环:

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

  2. else分支中,您执行ptr_ca--;,但在default中,您再次呼叫ptr_ca++;
    (请注意,即使使用break,您仍然会在循环结束时调用ptr_ca++;

在这两种情况下,指针都不会改变,所以一旦你最终进入任何这些条件,你的循环将永远不会退出。

可能的第三个问题

我只能猜测,因为从名称上看不出来,但似乎prv_ptr应该持有循环中的最后一个指针?如果是这样,那么您永远不更新该指针似乎是错误的。无论哪种方式,正确的变量名称都会更清楚地表明此指针的确切用途。(附带说明一下,一致使用const可以帮助识别此类问题。如果你有一个变量没有const,但从未更新,你要么忘记添加const,要么忘记更新它。

如何修复

设置代码格式:

  • 不要使用using namespace std;.
  • 每行一个语句。
  • 为您的变量提供正确的名称,以便轻松识别什么是什么。(这不是1993年,真的,我宁愿有thisIsThePointerHoldingTheCharacterThatDoesTheThing也不愿ptr_xy

修复上述问题(添加breaks,确保您的循环实际退出)。

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

祝你好运!

只需计算"R","G"和"B"字母的数量并从头开始填充数组。 更容易,没有递归。