编程珠玑2章B问题--n元一维向量向左旋转i个位置

问题:将一个n元一维向量向左旋转i个位置,要求使用一个n元的中间向量在n步内完成该工作,仅使用数十个额外字节的存储空间,在正比于n的时间内完成向量的旋转。

思路:

想法1:移动x[0]到临时变量t,然后移动x[i]至x[0],x[2i]至x[i],以此类推(将x中的所有下标对n取模),直至返回到取x[0]中的元素,此时改为从t取值然后终止过程。以此类推,直至把x[0]至x[i-1]个变量移动。

想法2:问题可以理解为将数组ab转换成ba。从ab开始,首先对a求逆,得到a'b,然后对b求逆,得到a'b',最后整体求逆,得到(b'a')',就是ba。

代码:

想法1

 

#include <stdio.h>
#define MAXSIZE 10

void print(const int num[]);
void move(int num[],int move_num);
int gcd(int num,int move_num);

/*  打印信息*/
void print(const int num[])
{
    int tmp_index = 0;
    printf("(num) : ");
    while(tmp_index<MAXSIZE)
    {
        printf("%d ", num[tmp_index]);
        tmp_index++;
    }
    printf("\n");
}

/*  向左移动*/
void move(int num[],int move_num)
{
    int index = 0;//遍历次数的索引
    int times = gcd(MAXSIZE,move_num);//MAXSIZE和move_num的最大公约数,即遍历次数
    int tmp_value = 0;//存储当前遍历的第一个值的临时变量,表示t
    int tmp_index = 0;//向后移动move_num位的临时变量,表示x[i]中的i
    int tmp_index_index = 0;//向后移动k*move_num位的临时变量(k>=1),表示x[i*2]中的i*2

    for(index = 0;index< times;index++)//共遍历times次
    {
        tmp_value = num[index];
        tmp_index = index;
        while(1)
        {
            tmp_index_index = tmp_index + move_num;
            if(tmp_index_index >= MAXSIZE)//超过最大值,则减去最大值,剩余值表示新的位置
                tmp_index_index -= MAXSIZE;
            if(tmp_index_index == index)//与当前索引值相同,说明当前一次的遍历结束(否则,就会重复遍历相同位置),再次遍历下一个
                break;
            num[tmp_index] = num[tmp_index_index];//把x[2*i]的位置移动到x[i]上
            tmp_index = tmp_index_index;//探针移动到i*2上
        }
        num[tmp_index] = tmp_value;//把t值赋予相应的位置
        print(num);//打印每次遍历后的数组
    }
}

/*  求最大公约数*/
int gcd(int num,int move_num)
{
    return (!move_num)?num:gcd(move_num,num%move_num);
}
/*  主程序*/
int main()
{
    int num[MAXSIZE] = {0,1,2,3,4,5,6,7,8,9};
    int move_num = 0;
    char c;
    print(num);

    //输入向左移动次数(大于0)
    printf("Input times for moving left: ");
    while(scanf("%d",&move_num) != 1 || move_num <= 0 || move_num >= MAXSIZE)
    {
        printf("please input times (>0 and <MAXSIZE)!\n");
        while((c = getchar()) != '\n' && c != EOF);
        printf("Input times for moving left: ");
    }

    //移动move_num
    move(num,move_num);

    return 0;
}

 

想法1的时间复杂度为O(n),空间复杂度为O(n)

想法2

#include <stdio.h>
#define MAXSIZE 10

void print(const int num[]);
void move(int num[],int move_num);
void reverse(int num[],int start_pos,int end_pos);

/*  打印信息*/
void print(const int num[])
{
    int tmp_index = 0;
    printf("(num) : ");
    while(tmp_index<MAXSIZE)
    {
        printf("%d ", num[tmp_index]);
        tmp_index++;
    }
    printf("\n");
}

/*  向左移动*/
void move(int num[],int move_num)
{
    reverse(num,0,move_num-1);//翻转a,得到a'
    reverse(num,move_num,MAXSIZE-1);//翻转b,得到b'
    reverse(num,0,MAXSIZE-1);//翻转a'b'
}

/*  翻转
 *  @param
 *  num[]:数组
 *  start_pos:起始位置
 *  end_pos:终止位置
 */
void reverse(int num[],int start_pos,int end_pos)
{
    int tmp_value = 0;
    for(;start_pos<end_pos;start_pos++,end_pos--)    {
        tmp_value = num[start_pos];        num[start_pos] = num[end_pos];
        num[end_pos] = tmp_value;
    }
    print(num);
}
/*  主程序
 *  问题:将一个n元一维向量向左旋转i个位置,要求使用一个n元的中间向量在n步内完成该工作,
 *           仅使用数十个额外字节的存储空间,在正比于n的时间内完成向量的旋转。
 *  思路:问题可以理解为将数组ab转换成ba。从ab开始,首先对a求逆,得到a'b,然后对b求逆,得到a'b',最后整体求逆,得到(b'a')',就是ba。
 */
int main()
{
    int num[MAXSIZE] = {0,1,2,3,4,5,6,7,8,9};
    int move_num = 0;
    char c;
    print(num);

    //输入向左移动次数(大于0)
    printf("Input times for moving left: ");
    while(scanf("%d",&move_num) != 1 || move_num <= 0 || move_num >= MAXSIZE)
    {
        printf("please input times (>0 and <MAXSIZE)!\n");
        while((c = getchar()) != '\n' && c != EOF);
        printf("Input times for moving left: ");
    }

    //移动move_num
    move(num,move_num);

    return 0;
}


想法2的时间复杂度为O(n),空间复杂度为O(n)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值