C:子范围内的反向数组

时间:2012-02-14 03:10:16

标签: c arrays algorithm

我正在尝试使用此处描述的方法实现左数组旋转​​:http://www.cs.bell-labs.com/cm/cs/pearls/s02b.pdf(在反转算法部分下)

当起始索引不为0时,我无法反转数组。

这是我到目前为止所做的:

void reverse_arr(int *a, int start, int end)
{
    int i;
    int len = end - start;
    //printf("Len pre loop: %d\n", len);
    int swap;

    for(i = start; i < --len; i++)
    {
        //printf("start: %d\tlen: %d\n", start, len);
        swap   = a[i];
        a[i]   = a[len];
        a[len] = swap;
    }
}

当起始索引为0时,这很有效,但是当它是其他任何东西时,它永远不会反转所有元素。

前:

int test[] = {1,2,3,4,5,6};
reverse_arr(test, 0, 2); //reverse the first 2 elements of the array

结果为:{2,1,3,4,5,6}预期

int test[] = {1,2,3,4,5,6}; 
reverse_arr(test, 2, 6); //reverse the last 4 elements of the array

导致:{2,1,4,3,5,6}这是不期望的,只有3和4被逆转。

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:4)

您需要调整交换中的其他下标:

void reverse_arr(int *a, int start, int end)
{
    int len = end - start;

    for (int i = start; i < --len; i++)
    {
        int swap = a[i];
        a[i]     = a[i+len];
        a[i+len] = swap;
    }
}

你也可以使用:

void reverse_arr(int *a, int start, int end)
{
    int len = end - start;

    end--;

    for (int i = start; i < --len; i++, end--)
    {
        int swap = a[i];
        a[i]     = a[end];
        a[end]   = swap;
    }
}

工作测试代码

#if defined(VERSION1)
static void reverse_arr(int *a, int start, int end)
{
    int i;
    int len = end - start;
    int swap;

    for (i = start; i < --len; i++)
    {
        swap     = a[i];
        a[i]     = a[i+len];
        a[i+len] = swap;
    }
}

#else

static void reverse_arr(int *a, int start, int end)
{
    int i;
    int len = end - start;

    end--;

    for (i = start; i < --len; i++, end--)
    {
        int swap   = a[i];
        a[i]   = a[end];
        a[end] = swap;
    }
}
#endif

#define DIM(x)  (sizeof(x)/sizeof(x[0]))

#include <stdio.h>

static void print_array(int *array, size_t size)
{
    for (size_t i = 0; i < size; i++)
        printf(" %d", array[i]);
    putchar('\n');
}


static void tester(int lo, int hi)
{
    int test[] = {1,2,3,4,5,6};
    printf("Before: (%d, %d)\n", lo, hi);
    print_array(test, DIM(test));
    reverse_arr(test, lo, hi); //reverse the first 2 elements of the array
    printf("After:  (%d, %d)\n", lo, hi);
    print_array(test, DIM(test));
    putchar('\n');
}

int main(void)
{
    tester(0, 2);
    tester(2, 6);
    return(0);
}

使用-DVERSION1编译的结果是否相同:

Before: (0, 2)
 1 2 3 4 5 6
After:  (0, 2)
 2 1 3 4 5 6

Before: (2, 6)
 1 2 3 4 5 6
After:  (2, 6)
 1 2 6 4 5 3

答案 1 :(得分:3)

您应该完全放弃len,而是使用end。在您使用它时,您也可以放弃i,然后使用start。您的代码将以这种方式变得更具可读性:

void reverse_arr(int *a, int start, int end)
{
    int swap;
    while(start < end)
    {
        swap   = a[start];
        a[start++]   = a[--end];
        a[end] = swap;
    }
}

答案 2 :(得分:1)

这是因为您将ilen进行比较,如果它从0开始就没有问题,但如果它从其他任何地方开始就没有(基数值不同)。

例如,如果要从偏移12开始旋转三个字符,则在退出状态下for循环开始后不会发生任何事情。

快速解决方法是在开始循环之前简单地调整a,以便它有效地认为(本地值)a是数组的开头:

a += start;
for (i = start; i < --len; i++)  // No change on this line.