【我解C语言面试题系列】004 数组的循环右移问题

【我解C语言面试题系列】004 数组的循环右移问题

数组的循环右移

 

【题目】有一个整数数组,现要求实现这个整数数组的循环右移。如:12345 则循环右移两位后结果是:45123

 

方法一:(最最容易想到的办法)

void RightCircleShift_00(int buffer[],int shift)

{

    int i,j,tt;

   

    for(i=0;i<shift;i++)

    {

       tt = buffer[ARRSIZE-1];

       for(j=ARRSIZE-1;j>0;j--)

           buffer[j] = buffer[j-1]; 

       buffer[0] = tt;

    }

}

这个办法是用两个循环来控制,内循环每次向右移动一位,外循环则用来限制移动的位数。算法需要执行 ARRSIZE * ShiftValue次,时间复杂度是O( N2 )。

 

方法二:(由方法一得到的递归程序)

void RightCircleShift_01(int buffer[],int shift)

{

    int *p,tt;

   

    tt = *(buffer+ARRSIZE-1);

 

    for(p = buffer+ARRSIZE-1;p > buffer;p--)

       *p = *(p-1);

   

    *buffer = tt;

 

    shift--;

    if(shift > 0)

        RightCircleShift_00(buffer,shift);

}

这个程序跟方法一类似,区别就是它是用递归来实现的。同样需要执行ARRSIZE * ShiftValue次,时间复杂度也是O( N2 )。

 

方法三 

void RightCircleShift_02(int buffer[],int shift)

{

    int *title,*r,*p;

   

    if(shift == 0)

       return;

   

    shift = shift % ARRSIZE;

   

    title = (int *)malloc(sizeof(int)*shift);

    if( title == NULL )

       return;

   

    r = buffer + (ARRSIZE - shift);

    memcpy(title, r, shift * sizeof(int));

 

    p = buffer + shift;

    memmove(p, buffer, (ARRSIZE - shift) * sizeof(int));

    memcpy(buffer, title, shift * sizeof(int));

   

    free(title);

}

这个算法需要移动位数大小的临时辅助空间。如需移动两位,则申请两个的空间,然后把从右边起的两个元素拷贝的临时辅助空间,然后前面的元素向后移动两位,最后再把临时空间里面的两个元素拷贝到前面的两位即可完成循环右移。需要执行 ARRSIZE次,时间复杂度是O( N )。

 

方法四:

void RightCircleShift_03(int buffer[],int shift)

{  

    if(shift <= 0)

       return;

 

    if( (shift & 1) == 0)

    {

       BufferShiftEvenNumber(buffer,shift-1);

       BufferShiftEvenNumber(buffer,1);

    }

    else

       BufferShiftEvenNumber(buffer,shift);

       

}

void BufferRightShiftEvenNumber(int buffer[],int shift)

{

    int i,j,tt,res;

 

    res = buffer[0];

    for (i=0,j=0; i<ARRSIZE; i++)

    {

       tt = res;

       res = buffer[(j+shift)%ARRSIZE];

       buffer[(j+shift)%ARRSIZE] = tt;

       j = (j+shift) % ARRSIZE;

    }

}

这个算法并不需要开额外的辅助空间,而且时间复杂度同样也是O( N )。BufferRightShiftEvenNumber函数是这个算法的核心,该函数只能实现每次向右移动奇数位元素。如果要移动的位数是偶数的时候就需要把该数分解为两个奇数,n = (n 1) + 1 。

 

方法五:

void RightCircleShift_04(int buffer[],int shift)

{

    shift %= ARRSIZE;

    ReverseArray(buffer,1,ARRSIZE);

    ReverseArray(buffer,1,shift);

    ReverseArray(buffer,shift+1,ARRSIZE);

}

void ReverseArray(int buffer[],int start,int end)

{

    int i,tt;

 

    if(end > ARRSIZE)

       return;

 

    start -= 1;

    end -= 1;

    while(start < end)

    {

       tt = buffer[start];

       buffer[start++] = buffer[end];

       buffer[end--] = tt;

    }

}

这个办法也是很不错,需要两次扫描数组即可,时间复杂度O(N)。这个办法跟 方法四 移动偶数个元素的情况一样,都是需要两次扫描数组。当然如果是移动奇数个元素的话,则不如方法四有效,方法四只需要扫描一次数组就可以了。

算法是网友 luodongshui 提出的:

1、 先将整个数组反转。

2、 然后再反转前shift个元素。

3、 接着再反转后N-shift个元素。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值