数组循环向左移动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"%d ",a[i]);
    }
}

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

//方法一:颠倒交换法
void fun1(int len,int k){
    int i=0;
    for(i=0;ireverse(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时 画个图把代码走一遍,看下面的图
    数组循环向左移动k位的算法_第1张图片
  • 情况2 针对len%k==0
    让count用来计数循环的趟数, 比如 len=10, k=2 时,count范围从0~1 循环两次
    内层循环 使用 i 和 j 来循环赋值,当回到count下标位置时,这一趟赋值完成,继续下一趟

数组循环向左移动k位的算法_第2张图片

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

代码:

//方法二: 循环移动法
void fun2(int len,int k){
    int i;
    for(i=0;iint 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;countcount++){ //循环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时, 如图
数组循环向左移动k位的算法_第3张图片


void fun3(int len,int k){

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

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

        if(jcount==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长度的数组
}

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

你可能感兴趣的:(数组循环向左移动k位的算法)