用C打造明星印刷的方式很难

时间:2013-10-14 20:09:50

标签: c algorithm recursion geometry

我已经开始练习一些C并找到了这个很好的练习,我必须通过输入打印一个三角形。 对于输入6,它将打印

*
**
***
****
*****
******
*****
****
***
**
*

现在,看着它,我想,嗯,这不是一项艰巨的任务。所以我决定尝试使用递归,没有循环和只有2个变量来编写它。 该函数应如下所示:

void PrintTriangle(int iMainNumber, int iCurrNumber)
{
   //Logic goes here
}

几个小时后,我意识到这比我想象的要困难得多,因为我需要为函数传递足够的信息,以便能够“记住”应该打印多少个三角形。

所以现在我决定问你是否可能。

(记住,没有循环,没有其他功能,只有递归)。

修改 这不是功课,这纯粹是出于好奇心。但是我可能无法为您验证。 我已经成功地完成了这个

void PrintTriangle(int iMainNumber, int iCurrNumber)
{
    if (iMainNumber == 0)
    {
        printf("\r\n");
    }
    else if (iMainNumber == iCurrNumber)
    {
        printf("\r\n");
        PrintTriangle(iMainNumber - 1, 0);
    }
    else
    {
        printf("%s", MYCHAR);
        PrintTriangle(iMainNumber, iCurrNumber + 1);
    }
}

我试图创建相反的函数时遇到困难,我相信如果我能做到这一点,我将能够使用iMainNumber和iCurrNumber在函数流中导航的正面或负面的事实。

换句话说,当参数为负时,我会在输入长度减去1时打印一颗降星,当参数为正时,我会在输入长度中打印升序星。

我考虑过使用标志,但不是2个整数。

也许如果我添加另一个标志并且有2个整数和一个标志然后我可以解决它,但正如我所说,我试图将自己限制为2个整数。

我开始想到的是,如果不使用超过2个整数和递归,就无法传递在此方法中打印升序星所需的信息。

但我仍然不太确定,因此问题。

5 个答案:

答案 0 :(得分:3)

使用相同数量的变量进行递归可以完成循环。您只需要弄清楚状态是什么,并在递归调用中传递更新状态,而不是循环。

首先让我们迭代一次。输入为size,即三角形的大小。我们有两个状态变量,{1}从1到lineNumbersize*2-1从1到columnNumber。请注意:

size

迭代版本将是这样的:

columnsForLine = lineNumber <= size ? lineNumber : size*2 - lineNumber

does indeed work。现在如何递归?只是弄清楚状态正在更新的地方,并将其作为递归调用:

int lineNumber = 1;
int columnNumber = 1;
int size = 6;
while (lineNumber <= size*2-1) {        
    printf("*");
    int columnsForLine = lineNumber <= size ? lineNumber : size*2 - lineNumber;
    if (columnNumber == columnsForLine) {
        printf("\n");
        columnNumber = 1;
        lineNumber += 1; 
    }
    else {
        columnNumber += 1;
    }
}

voila。可用于任何尺寸,例如13

请注意,代码基本相同,只是以不同方式执行控制流程。另请注意,这是尾递归的,这意味着智能编译器可以执行递归调用而不会为每次调用增加堆栈。


嗯,如果你只想使用2个变量,包括输入,将会有点棘手...你总是可以欺骗并将所有3个整数填充到一个整数中,然后解压缩它每次重新包装。 e.g。

void recstars(int size, int lineNumber, int columnNumber) {
    if (!(lineNumber <= size*2 - 1)) {
        return;
    }
    printf("*");
    int columnsForLine = lineNumber <= size ? lineNumber : size*2 - lineNumber;
    if (columnNumber == columnsForLine) {
        printf("\n");
        recstars(size, lineNumber + 1, 1);
    }
    else {
        recstars(size, lineNumber, columnNumber + 1);
    }
}
recstars(6, 1, 1);

Seems to work。你认为那是合法的吗?

否则,棘手的部分不是递归,它只是通过状态只有2个整数来完成工作。你能用2个整数迭代地做吗?

答案 1 :(得分:3)

我想出了:

void PrintTriangle(int size, int indent)
{
    switch(size) {
    case 0:
        if (indent > 1) PrintTriangle(size, indent-1);
        putchar('*');
        break;
    case 1:
        PrintTriangle(size-1, indent+1);
        putchar('\n');
        break;
    default:
        PrintTriangle(1, indent);
        PrintTriangle(size-1, indent+1);
        PrintTriangle(1, indent);
        break; }
}

int main()
{
    PrintTriangle(6, 0);
    return 0;
}

作为快速的第一次尝试。似乎可以完成这项工作。

size是要打印的三角形的大小,indent是在三角形的每一行之前打印的额外星星的数量。 size==0表示只打印indent个星号,没有换行符(用于在三角形之前打印缩进)

如果你想要更紧凑的东西,可以将其重写为:

void PrintTriangle(int size, int indent)
{
    if (size <= 0) {
        if (indent > 1) PrintTriangle(size, indent-1);
        putchar('*');
    } else {
        if (size > 1) PrintTriangle(1, indent);
        PrintTriangle(size-1, indent+1);
        if (size > 1) PrintTriangle(1, indent);
        else putchar('\n'); }
}

答案 2 :(得分:1)

使用2个参数作为OP建议

void PrintTriangle(int iMainNumber, int iCurrNumber) {
  if (iMainNumber < 0) { // Row (use negative iMainNumber)
    printf("%c", '*');
    PrintTriangle(iMainNumber + 1, 0);
    if (iMainNumber == -1)
      printf("\n");
  } else if (iMainNumber > 0) { 
    if (iCurrNumber < iMainNumber) { // Preceding short lines
      if (iCurrNumber > 1)
        PrintTriangle(iMainNumber, iCurrNumber - 1);
      PrintTriangle(-iCurrNumber, 0);
    } else if (iCurrNumber == iMainNumber) { 
      PrintTriangle(iMainNumber, iCurrNumber - 1);  // left
      PrintTriangle(iMainNumber, iCurrNumber + 1);  // Right
    } else {                         // Subsequent short lines
      if ((iCurrNumber - iMainNumber) < iMainNumber)
        PrintTriangle(iMainNumber, iCurrNumber + 1);
      PrintTriangle(-(iCurrNumber - iMainNumber), 0);
    }
  }
}

int main() {
  PrintTriangle(3,3);
  PrintTriangle(6,6);
  return 0;
  }

答案 3 :(得分:0)

根据我的阅读,大多数建议已经指出要传递你需要的任何状态。

但是,你真的不需要那么多的分支语句。您需要的大部分内容都可以通过算术得出。您可以计算递归总数,并从当前递归计数中获取星数。此外,通过将初始调用的部分与递归分开,可以使使用更加简单。

刚看到你不想要两个以上的整数。考虑下面的内容,看看你是否真的想保持这种偏好。如果是这样,您可以在递归部分中计算总计。我认为它的可读性会降低。

void _print_stars(int height, int total, int current)
{
    int stars = current <= height ? current : 2 * height - current;

    for (int i = 0; i < stars; i++) { printf("*"); }
    printf("\n");

    if (current != total)
    {
        _print_stars(height, total, current + 1);
    }
}

void print_stars(int height)
{
    int total_recursions = 2 * height - 1;
    _print_stars(height, total_recursions, 1);
}

答案 4 :(得分:0)

纯递归,没有循环,调用程序'main()'只传递一个参数:

void PrintTheClms(int width, int stars) {
    printf("*");
    if stars < width then {
      PrintTheClms(width, stars+1);
    }
}

void PrintStars(int  width) {
    PrintTheClms(width, 1);
    printf("\n");
}

void PrintTheRows(int size, int indent) {
    PrintStars(indent);
    if indent < size then {
      PrintTheRows(size, indent+1);
      PrintStars(indent);
    }
}

void PrintTriangle(int size) {
    if size > 0 then {
      PrintTheRows(size, 1);
    }
}

int main() {
    PrintTriangle(6);
    PrintTriangle(11);
    // etc.
    return 0;
}

非常简单 - 没有else子句,没有case构造,没有方向标志。但是,很多过程和很多电话。