C 在不使用迭代的情况下反转数组

C 在不使用迭代的情况下反转数组,c,algorithm,C,Algorithm,今天有人问我一个问题,我认为这是不可能的,但我可能是错的,或者是想得太多了。如何在不使用C中的迭代的情况下反转数组 我的想法是,这是不可能的,因为数组可以是任意大小的,并且没有一个C程序可以在不使用某种形式的迭代的情况下表达这种支持。使用递归函数。 void reverse(int a[],int start,int end) { int temp; temp = a[start]; a[start] = a[end]; a[end] = temp;

今天有人问我一个问题,我认为这是不可能的,但我可能是错的,或者是想得太多了。如何在不使用C中的迭代的情况下反转数组


我的想法是,这是不可能的,因为数组可以是任意大小的,并且没有一个C程序可以在不使用某种形式的迭代的情况下表达这种支持。

使用递归函数。

void reverse(int a[],int start,int end)
{
     int temp;
     temp = a[start];
     a[start] = a[end];
     a[end] = temp;


    if(start==end ||start==end-1)
       return;
    reverse(a, start+1, end-1);
}

只需将上述方法称为反向(array,0,lengthofarray-1)正如人们在评论中所说的,它取决于迭代的定义

案例1。迭代作为一种编程风格,不同于递归 如果将递归(简单地)作为迭代的替代方案,那么Kalai提出的递归解决方案就是正确的答案

案例2。作为下限线性时间的迭代 如果将迭代视为“检查每个元素”,那么问题就变成了阵列反转是需要线性时间,还是可以在次线性时间内完成

表示不存在阵列反转的次线性算法,考虑具有n个元素的数组。假设存在一个算法A用于反转,该算法不需要读取每个元素。然后,对于

0..n-1
中的一些
i
存在一个元素
a[i]
,该元素算法从未读取,但仍然能够正确反转数组。(编辑:我们必须排除奇数长度数组的中间元素——请参见此范围内的下面注释——请参见下面的注释——但这并不影响渐进情况下的算法是线性还是次线性。)


由于算法从不读取元素
a[i]
,因此我们可以更改其值。假设我们这样做。然后,算法,从来没有读过这个值,将产生与我们改变它的值之前相同的反转答案。但是这个答案对于
a[i]
的新值是不正确的。因此,不存在至少不读取每个输入数组元素(保存一个)的正确反转算法。因此,数组反转的下限为O(n),因此需要迭代(根据此场景的工作定义)

(请注意,此证明仅适用于数组反转,不适用于真正具有次线性实现的算法,如二进制搜索和元素查找。)

案例3。作为循环构造的迭代
如果迭代被视为“循环直到满足一个条件”,那么这将转化为带有条件跳转的机器代码,已知这需要一些严重的编译器优化(利用分支预测等)。在这种情况下,如果有人询问是否有一种方法可以“不迭代”地完成某些事情,可能会考虑循环展开(对于直线代码)。在这种情况下,原则上您可以编写直线(无循环)C代码。但是这种技术不是通用的;只有在您事先知道数组的大小时,它才起作用。(很抱歉在答案中添加这种或多或少轻率的情况,但我这样做是为了完整性,因为我听过“迭代”这个术语。)以这种方式使用,循环展开是重要的编译器优化。)

你的问题的答案是,是的,不需要迭代就可以反转数组。问题本身的措辞可能有歧义,但是,问题的精神是显而易见的:可以使用递归算法;从这个意义上讲,递归的含义一点也不含糊

如果在一家顶级公司的面试中,你被问到这个问题,那么下面的伪代码足以证明你真正理解递归的含义:

function reverse(array)

    if (length(array) < 2) then
        return array

    left_half = reverse(array[0 .. (n/2)-1])
    right_half = reverse(array[(n/2) .. (n-1)])

    return right_half + left_half

end
使用递归算法解决的任何问题都遵循“分而治之”范式,即:

  • 问题被划分为[两个或更多]子问题,其中每个子问题都比原始问题小,但可以以类似的方式解决(划分

  • 问题分为[两个或多个]子问题,每个子问题都是独立的,可以递归解决,如果足够小(征服),也可以直接解决

  • 将问题分为[两个或多个]子问题,将这些子问题的结果进行组合,以给出原始问题的解决方案(组合

  • 上面用于反转数组的伪代码严格满足上述条件。因此,可以将其视为递归算法,我们可以毫无疑问地声明,可以不使用迭代来反转数组。


    其他背景信息
    迭代、递归实现和递归算法之间的区别

    递归实现意味着算法是递归的,这是一个常见的误解。它们不是等价的。下面是一个关于原因的明确解释,包括对上述解决方案的详细解释



    什么是迭代和递归?

    早在1990年,三位最受尊敬的计算机科学领域的现代算法分析学者,以及,发表了他们广受好评的文章。在这本书中,代表了200多篇受尊敬的文章以他们自己的方式汇集在一起,20多年来,这本书一直被用作第一本也是唯一一本教授算法的文章在世界上大多数顶尖大学中,MSSR、Cormen、Leiserson和Rivest都明确说明了什么是迭代,什么是递归

    在分析和比较两种经典排序算法(插入排序和合并排序)时,他们解释了迭代和递归算法(有时称为增量算法)的基本特性
                       Original Input
    
    1.                ABCDEFHGIJKLMNOP                   Recurse
    2.        ABCDEFGH                IJKLMNOP           Recurse
    3.    ABCD        EFGH        IJKL        MNOP       Recurse
    4.  AB    CD    EF    GH    IJ    KL    MN    OP     Recurse
    
    5. A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P    Terminate
    
    6.  BA    DC    FE    HG    JI    LK    NM    PO     Reverse
    7.    DCBA        HGFE        LKJI        PONM       Reverse
    8.        HGFEDCBA                PONMLKJI           Reverse
    9.                PONMLKJIHGFEDCBA                   Reverse
    
                      Reversed Output
    
    function insertionSort(array)
    
        if (length(array) == 1)
            return array
        end
    
        itemToSort = array[length(array)]
        array = insertionSort(array[1 .. (length(array)-1)])
    
        find position of itemToSort in array
        insert itemToSort into array
    
        return array
    
    end
    
    function reverse(array)
    
        for each index i = 0 to (length(array) / 2 - 1)
            swap array[i] with array[length(array) - i]
        next
    
    end
    
                       Original Input
    
    1.                ABCDEFHGIJKLMNOP                   Divide
    2.        ABCDEFGH                IJKLMNOP           Divide
    3.    ABCD        EFGH        IJKL        MNOP       Divide
    4.  AB    CD    EF    GH    IJ    KL    MN    OP     Divide
    
    5. A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P    Terminate
    
    6.  BA    DC    FE    HG    JI    LK    NM    PO     Conquer (Reverse) and Merge
    7.    DCBA        HGFE        LKJI        PONM       Conquer (Reverse) and Merge
    8.        HGFEDCBA                PONMLKJI           Conquer (Reverse) and Merge
    9.                PONMLKJIHGFEDCBA                   Conquer (Reverse) and Merge
    
                      Reversed Output
    
    function reverse(array)
    
        /* check terminating condition. all single elements are also reversed
         * arrays of unit length.
         */
        if (length(array) < 2) then
            return array
    
        /* divide problem in two equal sub-problems. we process the sub-problems
         * in reverse order so that when combined the array has been reversed.
         */
        return reverse(array[(n/2) .. (n-1)]) + reverse(array[0 .. ((n/2)-1)])
    
    end
    
    function reverse(array)
    
        if length(array) < 2
            return
        end
    
        swap array[0] and array[n-1]
        reverse(array[1..(n-1)])
    
    end
    
    /* Use recursion to reverse an array */
    function reverse(a){
        if(a.length==undefined || a.length<2){
            return a;
        }
        b=[];
        b.push(reverse(copyChop(a)));
        b.push(a[0]);
        return b;
        /* Return a copy of an array minus the first element */
        function copyChop(a){ 
            b=a.slice(1); 
            return b;
        }
    }
    
    reverse([1,2,3,4]);
    
       #include<stdio.h>
    
    
       void rev(int *a,int i,int n)
      {
    
    if(i<n/2)
    {
        int temp = a[i];
        a[i]=a[n-i-1];
        a[n-i-1]=temp;
        rev(a,++i,n);
     }
    }
    int main()
        {
        int array[] = {3,2,4,5,6,7,8};
       int len = (sizeof(array)/sizeof(int));
       rev(array,0,len);    
       for(int i=0;i<len;i++)
       {
        printf("\n array[%d]->%d",i,array[i]);
      }
    }