【问题标题】:Can this two recursive functions be merged into one?这两个递归函数可以合并为一个吗?
【发布时间】:2021-10-11 21:49:47
【问题描述】:
    int sorted_a(int arr[], int N)
    {

        if (N == 1 || N == 0)
            return 1;
        if (arr[N - 1] < arr[N - 2])
        {
            return 0;
        }

        return sorted_a(arr, N - 1);
    }

    int sorted_d(int arr[], int N)
    {

        if (N == 1 || N == 0)
            return 1;
        if (arr[N - 1] > arr[N - 2])
        {
            return 0;
        }

        return sorted_d(arr, N - 1);
    }

这是两个单独的递归函数,用于检查数组是按升序还是降序排序(它们为每种情况返回一个),我似乎找不到只使用一个来完成这项工作的方法(该函数必须仅当无论顺序如何(升序或降序)都已排序时才返回 1。有什么帮助吗?

编辑: 也许我的问题不够清楚。我只想创建一个问题,仅当数组已排序时才返回 1(无论升序/降序的排序方向),否则返回 0。

【问题讨论】:

  • int sorted(int arr[], int N, int direction); ... sorted(a, 10, -1) 相当于sorted_d(a, 10)
  • 你这是什么意思
  • 如果你想要一个多算法函数,你需要提供一种机制来指定算法选择到其中的代码(通过参数或者,可怕的是,通过其他方式,如全局)。但我怀疑这并不能回答你的问题,因为我不相信你清楚你在问什么。你说:“我似乎无法找到一种方法,只使用一个来完成这项工作。”嗯……“工作”??当您询问如何制作一个可以根据要求执行 either 的功能时,我们读到了这一点。 (因此一种将 which 指定为函数参数的方法)。如果不是这种情况,您需要澄清您的问题。
  • 为什么要用递归函数?
  • @4386427 - 可能出了什么问题? :-)

标签: arrays c sorting


【解决方案1】:

由于大多数解决方案一次只处理一个升序/降序,或者对我来说似乎过于复杂,因此这里有一个 [非递归] 版本,可在单个函数中单次测试升序/降序:

int
sorted(const int *arr,int N)
{
    int sorted = 0x03;

    do {
        if (N < 2)
            break;

        int prev = arr[0];
        int cur;

        for (int idx = 1;  idx < N;  ++idx, prev = cur) {
            cur = arr[idx];

            // get difference
            int dif = cur - prev;

            // the same -- no change in state
            if (dif == 0)
                continue;

            // one of the sort directions is [now] wrong
            if (dif < 0)
                sorted &= 0x01;
            else
                sorted &= 0x02;

            // both directions are unsorted -- stop early
            if (! sorted)
                break;
        }
    } while (0);

    return sorted;
}

【讨论】:

    【解决方案2】:

    首先,将原始函数转换为循环以摆脱递归。例如。第一个是:

    int sorted_a(int arr[], int N) {
        while(N > 1) {
            if (arr[N - 1] < arr[N - 2]) {
                return 0;
            }
            N--;
        }
        return 1;
    }
    

    下一个;添加 2 个标志,一个用于“仍然可能上升”,另一个用于“仍然可能下降”,这样您就可以将所有内容合并到一个函数中:

    int sorted(int arr[], int N) {
        int a = 1;
        int d = 1;
    
        while(N > 1) {
            if( a != 0) {
                /* Still possibly ascending */
                if (arr[N - 1] < arr[N - 2]) {
                    if( d != 0) {
                        /* Not ascending and can't be descending */
                        return 0;
                    }
                    a = 0;   /* Not ascending (but could still be descending) */
                }
            }
            if( d != 0) {
                /* Still possibly descending */
                if (arr[N - 1] > arr[N - 2]) {
                    if( a != 0) {
                        /* Not descending and can't be ascending */
                        return 0;
                    }
                    d = 0;   /* Not descending (but could still be ascending) */
                }
            }
            N--;
        }
        return 1;
    }
    

    这个版本可能比只有 2 个单独的版本要慢(除了不太可能的情况 - 例如,当数组以相同的数字开始时重复很多次,比如 {1, 1, 1, 1, 1, ... 一直持续到它大于缓存)。尽管如此,它仍然是您问题的可行答案(“是的,它们可以合并!”)。

    但是;在循环内部只有 3 种情况(仍然可能上升或下降,仍然可能上升但不下降,仍然可能下降而不上升)。这意味着您可以将合并后的版本拆分为 3 个部分,以避免一些 (if(a == 0)) 分支,也可以去掉这些标志,例如:

    int sorted(int arr[], int N) {
        if(N < 2) {
            return 1;
        }
        while(N > 1) {
            if (arr[N - 1] != arr[N - 2]) {
                if (arr[N - 1] > arr[N - 2]) {
                    return sorted_a(arr, N-1);
                } else {
                    return sorted_d(arr, N-1);
                }
            }
            N--;
        }
        return 1;
    }
    
    int sorted_a(int arr[], int N) {
        while(N > 1) {
            if (arr[N - 1] < arr[N - 2]) {
                return 0;
            }
            N--;
        }
        return 1;
    }
    
    int sorted_d(int arr[], int N) {
        while(N > 1) {
            if (arr[N - 1] > arr[N - 2]) {
                return 0;
            }
            N--;
        }
        return 1;
    }
    

    这是我能想到的最快的(但我不认为“当它有助于性能时合并,但当它损害性能时不合并”是您要求的,所以..)。

    【讨论】:

      【解决方案3】:

      任务,即检查数组是否排序,不是使用递归函数来解决的任务。请改用简单的for/while 循环。

      进一步 - 为什么要花时间将两个功能合并为一个?好的编程实际上是将东西分成简单的函数。你已经有了两个简单的函数,所以你可以这样做:

      int sorted(int arr[], int N)
      {
          return sorted_a(arr, N) || sorted_d(arr, N);
      }
      

      也就是说,在某些情况下(对于性能和/或资源使用而言)使用单个“更复杂”的函数而不是多个简单的函数是有意义的。然而,这并不适用于这里,因为方法(即递归函数)从一开始就是错误的。

      无论如何 - 您的两个函数可以合并,但生成的代码非常糟糕

      这是一个示例,但不要这样做

      int sorted(int* arr, int N)
      {
      
          if (N < 2) return 1;
          if (arr[0] == arr[1]) return sorted(arr+1, N - 1);
          
          if (arr[0] > arr[1])
          {
              if (arr[N - 1] > arr[N - 2])
              {
                  return 0;
              }
          }
          else
          {
              if (arr[N - 1] < arr[N - 2])
              {
                  return 0;
              }
          }
      
          return sorted(arr, N - 1);
      }
      

      使用for/while 代替递归。

      【讨论】:

        【解决方案4】:

        一种直接的方法是向函数添加一个参数,该参数将指定检查数组的排序顺序。

        这是一个演示程序。

        #include <stdio.h>
        
        int sorted( const int a[], size_t n, int ascending )
        {
            return n < 2 || ( ( ascending ? !( a[1] < a[0] ) : !( a[0] < a[1]) ) &&
                                sorted( a + 1, n - 1, ascending   ) );
            
        }
        
        int main(void) 
        {
            int a[] = { 1, 1, 2, 2, 3, 3 };
            size_t n = sizeof( a ) / sizeof( *a );
            
            printf( "a[] is sorted - %s\n", sorted( a, n, 1 ) ? "true" : "false" );
        
            int b[] = { 3, 3, 2, 2, 1, 1 };
            n = sizeof( b ) / sizeof( *b );
            
            printf( "b[] is sorted - %s\n", sorted( b, n, 0 ) ? "true" : "false" );
        
            int c[] = { 3, 3, 1, 1, 2, 2 };
            n = sizeof( c ) / sizeof( *c );
            
            printf( "c[] is sorted - %s\n", sorted( c, n, 1 ) ? "true" : "false" );
        
            return 0;
        }
        

        程序输出是

        a[] is sorted - true
        b[] is sorted - true
        c[] is sorted - false
        

        【讨论】:

        • 如果数组从用户那里获取值怎么办?
        • @MemeGod 还有什么?有什么问题?
        • 它可以工作,但是你需要调用它两次来检查“它是否按顺序排序(升序或降序))”,所以它与拥有两个函数没有什么不同
        • @4386427 是的,你需要。
        猜你喜欢
        • 2021-09-27
        • 1970-01-01
        • 1970-01-01
        • 2012-06-13
        • 2018-12-11
        • 1970-01-01
        • 2012-12-14
        • 2016-12-30
        • 2017-07-09
        相关资源
        最近更新 更多