数组循环向左移动k位的算法

数组循环向左移动k位的算法, 我在课本上只看到了方法一,暂且称为颠倒交换法, 方法二是我自己想出来的,暂且称为循环赋值法.

方法一:颠倒交换法

算法描述:循环左移k位, 先把前面 0 到 k-1位置的数字首尾交换, 然后再把 k 到 len-1位置首尾交换, 最后再把 0 到 len-1下标位置首位交换即可实现, 这里的原理你可以画个例子就懂了

代码:

int a[100]; //数组是全局变量

//输出0到len位置的元素
void show(int len){
    for(int i=0;i<len;i++){
        printf("%d ",a[i]);
    }
}

//首尾交换的函数
void reverse(int left,int right){
    int i=left,j=right;
    while(i<j){
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
        i++;
        j--;
    }
}

//方法一:颠倒交换法
void fun1(int len,int k){
    int i=0;
    for(i=0;i<len;i++)
        a[i] = i;

    reverse(0,k-1);
    reverse(k,len-1);
    reverse(0,len-1);

    show(len); //输出len长度的数组
    printf("\n\n");
}

方法二:循环赋值法

这个方法是我自己想出来的, 也很感谢@木落兮帮我指正的错误, 如果还有错误的地方, 欢迎各位评论指正错误
算法描述:

  • 情况1:针对len%k!=0
    举个例子,len=5, k=3时 画个图把代码走一遍,看下面的图
    这里写图片描述
  • 情况2 针对len%k==0
    让count用来计数循环的趟数, 比如 len=10, k=2 时,count范围从0~1 循环两次
    内层循环 使用 i 和 j 来循环赋值,当回到count下标位置时,这一趟赋值完成,继续下一趟

这里写图片描述

综上所述,这个算法循环了k趟, 每趟循环 len/k 次, 时间复杂度O(n), 空间复杂度O(1)

代码:

//方法二: 循环移动法
void fun2(int len,int k){
    int i;
    for(i=0;i<len;i++)
        a[i] = i;

    int j,temp = a[0];
    i=0;
    if(len%k!=0){  //情况一:如果len不是k的整数倍
        int temp = a[0];
        while(true){
            j = (i+k)%len; //j取i后面的k+i位置,如果超出范围,则取余
            if(j==0) //如果循环一大圈,则说明已经赋值完成了就break,但是这个方法针对len%k==0的情况失效,所以while循环套在if判断里面
                break;
            a[i] = a[j];
            i = j;
        }
        a[i] = temp;
    }
    else{ //情况二:如果len是k的整数倍,由于上述情况不能适用于整数倍的情况
        for(int count=0;count<k;count++){ //循环k趟
            i = count;
            temp = a[i]; //记录开始的位置
            while(true){
                j = (i+k)%len;
                if(j==count) break; //回到这个位置时,则跳出循环
                a[i] = a[j];
                i = j;
            }
            a[i] = temp;
        } //end for

    } //end if

    show(len); //输出len长度的数组

}

附录:方法二的修改版, 压缩为一个循环

算法描述:
当len=8, k=2时, 如图
这里写图片描述


void fun3(int len,int k){

    int i;
    for(i=0;i<len;i++)
        a[i] = i;

    int j , temp = a[0];
    i=0;
    int count = 0; //循环的趟数,循环k次
    int pos = 0; //标记每趟循环开始的位置

    while(true){
        j = (i+k)%len;

        if(j<k && ++count==k) //标记循环的趟数,超过k次,则跳出循环
            break;

        if(j==pos){  // 如果j与pos重合,就说明是len%k==0的情况,则让a=j+1,再来一趟循环
            a[i] = temp;
            i=j+1;
            temp = a[i];
            pos = i; //标记这一趟开始的位置
            continue; //跳过下面两行代码
        }
        a[i] = a[j];
        i = j;

    } //end while

    a[i] = temp; //这一句代码针对len%k!=0的情况,让最后一个位置赋值

    show(len); //输出len长度的数组
}

如果你觉得算法有待改进的地方, 可以在下面评论。

  • 15
    点赞
  • 78
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值