【问题标题】:void function(no printing)- reverse a string using recursionvoid 函数(不打印)- 使用递归反转字符串
【发布时间】:2015-01-03 11:11:11
【问题描述】:

我想用 C 语言编写一个递归函数来反转一个单词。我知道如何打印它,但实际上我不知道如何反转原始单词。 所以,我想编写一个函数来反转一个单词,使用指针,使用 string.h,但必须是 void,不打印,并更改原始单词。函数原型: 无效反向(字符*字符串); 我能写的是递归的停止项(我不确定它们是否正确);

if(!string) return; // if the string is empty
if(*(string+1)=='\0' return (*string); // if there is only on char in the string
if(*(string+2))=='\0' // if there are only 2 letters In the strings-swap
temp=(*string);
(*string)= * (string+1);
(*string+1)= temp; // I don't know what to do after..

如果大家可以向我解释该怎么做,那就太好了。 谢谢。

【问题讨论】:

  • 如果你添加一个函数头来查看接口以及局部变量定义会很有用。
  • 你想在递归调用还是循环中回答?
  • @Karthikeyan.R.S 递归调用
  • 这应该是颠倒一个句子中的 words 还是颠倒一个 string ?你的描述不清楚。 “句子中的单词倒转”==>“单词中的句子 A 倒转”。而“反转字符串”==>“gnirtS A esreveR”。 究竟是什么? (注意,前者比后者困难得多)。
  • @ WhozCraig 你是对的,不清楚.. 我刚刚编辑了它。只是颠倒一个词..不是一个句子。

标签: c


【解决方案1】:

尾递归的实现:

#include <stdio.h>
#include <string.h>

/* function prototypes */
void reverse(char *string);
void reverseWorker(char *string, int start, int end);

int main(int argc, const char *argv[]) {
  char string[] = "Hello, world.";
  printf("string (original) = %s\n", string);
  /*
  reverse(string);

  Or, to reverse each word in the string...
  */

  char *ptr = strtok(string, " ");
  while(ptr != NULL) {
    reverse(ptr);
    ptr = strtok(NULL, " ");
    if(ptr != NULL)
      *(ptr-1)=' ';
  }

  /* the rest is the same */

  printf("string (reversed) = %s\n", string);
  return 0;
}

void reverse(char *string) {
  reverseWorker(string, 0, strlen(string)-1);
}

void reverseWorker(char *string, int start, int end) {
  /* terminal condition */
  if(start>=end)
    return;
  /* swap */
  char temp = string[start];
  string[start]=string[end];
  string[end]=temp;
  /* recursive step */
  reverseWorker(string,start+1,end-1);
}

【讨论】:

  • 您好,感谢您的帮助。但我不使用尾递归..只是我写的函数。只是一个词,而不是一个句子。就我所知,你能解释一下函数背后的逻辑是什么吗?我的意思是算法。
  • 使用开始和结束“指针”(在这种情况下,它们是字符数组的索引),交换开始和结束位置的字符,并通过将开始和结束移动到更靠近彼此一个;当 start 和 end 相遇时终止递归。您的交换是正确的,但仅限于特定的开始和结束。
  • 你能告诉我你所说的代码是什么意思吗?这对我来说真的很重要,我不能罚款任何可以向我解释的人。还有,主要功能是什么?
  • 那么,你只需要反转字符串中的一个单词,还是单独反转每个单词?
  • @Danny Daglas 就一个字
【解决方案2】:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

void reversefill(char*const from,char*const to){
    if(from>=to){
        //Nothing to do. Odd lengths get to from==to.
        //Even lengths 'swap over'.
        //Pointer comparison guaranteed legit - in the same array.
        return;
    }
    //Textbook swap.
    //Could use the classic xor swap trick.
    //However that will just confuse in this example.
    const char temp=*from;
    *from=*to;
    *to=temp;

    //Carry on moving our 'work' points closer together from both ends.
    reversefill(from+1,to-1);
}

void reverse(char* str){
    const size_t sz=strlen(str);
    if(sz==0){
        return;//Can't use str-1 - UB.
        //Could head for the door if sz==1 but this is a training example on recursion.
        //So we'll just show it works if from==to.
    }
    reversefill(str,str+sz-1);
}

int main() {
    char*const str="Hello World!";
    char*const rev=malloc(strlen(str)*sizeof(*str));//sizeof not required but good habit

    strcpy(rev,str);

    reverse(rev);

    printf("%s\n",rev);

    free(rev);//Don't listen to smart-arses who say that's unnecessary. 
    //Unless you really need to use the trick...
    //However examples should be the cleanest possible code.

    return EXIT_SUCCESS;
}

我认为要求是就地反转。

做到这一点的唯一方法(我认为 OP 意识到)是从两端开始工作并交换“对称”位置。也就是将第一个与最后一个交换,第二个与倒数第二个交换,等等。

这很好,但我们需要意识到我们什么时候在中间“相遇”了。 这对于奇数长度的情况很明显 - 两个工作点相遇。 即使在某些情况下,我们也需要发现“交叉”的工作原理。

这正是reversefill(,) 的工作原理。

我认为这段代码很好地体现了 C 字符串的优缺点。 main 函数非常高效。

但实际上必须扫描字符串两次,因为 C 本身并不提供 O(1) 获取字符串长度的方法!

【讨论】:

    【解决方案3】:

    你可以这样写函数

    void reverse( char s[] )
    {
        reverse_impl( s, strlen( s ) );
    }
    
    void reverse_impl( char s[], size_t n )
    {
        if ( !( n < 2 ) )
        {
            char c = s[0];
            s[0] = s[n-1];
            s[n-1] = c;
            reverse_impl( s + 1, n - 2 );
        }
    }
    

    但这是一个错误的解决方案,因为它不是函数void reverse( char s[] ); 是一个递归函数。函数void reverse_impl( char s[], size_t n ); 是递归的。但根据您的任务,函数void reverse( char s[] ); 必须是递归的。

    所以正确的解决方案如下。

    #include <stdio.h>
    
    void reverse( char s[] )
    {
        if ( *s  )
        {
            char *p = s;
            char c;
    
            do
            {
                        c = *p;
                        *p = *( p + 1 );
                        *( p + 1 ) = c; 
            } while ( *p++ );
    
            reverse( s );
    
            c = *p;
            *p = *( p - 1 );
            *( p - 1 ) = c;
        }
    }
    
    
    int main( void ) 
    {
        char s[] = "abcde";
    
        puts( s );
        reverse( s );
        puts( s );
    
        return 0;
    }
    

    输出是

    abcde
    edcba
    

    这个递归函数不使用标准函数:)

    【讨论】:

    • 嗨,非常感谢,但你使用循环和递归......我不能:(
    • @Tamar Kravitz 我认为你理解你的任务不正确。不要在分配中使用循环意味着该函数必须是递归的。但这并不意味着递归函数不能在自身内部使用循环。例如,相同的标准函数 strlen() 实际上是一个循环。
    • 我完全理解。我不能使用循环。
    • @Tamar Kravitz 你完全错了,因为你至少需要知道字符串的长度,并且没有循环 pr 函数 strlen 反过来又是一个循环,你不会找到字符串的长度。
    • @Tamar Kravitz 问题是你根本不理解我建议的算法。
    猜你喜欢
    • 2021-10-31
    • 1970-01-01
    • 2013-02-25
    • 2020-07-25
    • 2011-03-26
    • 2014-01-12
    • 1970-01-01
    • 2022-01-09
    相关资源
    最近更新 更多