C语言1008. 数组元素循环右移问题 (20)

原题: https://www.patest.cn/contests/pat-b-practise/1008

题意理解: 假设n=6, 需要活动的队是: 1 2 3 4 5 6, 如果m=2,
从6开始看, 把6
活动2独岗位, 6就顶了2底岗位, 同样把5平移2单职位, 5就到了1之职位,
依次类推.
脚考虑部分异样状况:
m=0, 很扎眼原列不进行其它活动
m=6, 把6变动6独岗位, 结果仍然是原来列
m=7, 现在m>n, 根据题意这种情形是唯恐的, 把6通向右边走7独岗位,
我们发现6换到了1底位置.
总结以上分析, 可以汲取, 移动的次数m = m % n

解题思路: 本题有多解法, 但不少法感觉不太道义或不顶合理.
第1栽, 不随便题目要求, 直接以2个数组.
第2种植, 利用C语言特性, 通过轮回一个一个读取数据,
读取一个数就由此测算把这个数额在合适
的职务, 利用这种方法, 简直可以实现数量”0″移动
第3种, 不开展数据移动, 而是控制打印顺序. 这个深好理解, 比如6个数, [1 2
3 4 5 6], m=2,
啊不怕是全往右侧走2只位置, 我们好事先打印5 6, 再打印1 2 3 4
第4栽, 使用链表实现, 这个措施感觉比较客观(下产生详尽说明)
第5种植, 使用数组模拟链表实现, 用链表实现代码量可能那个丰富,
用数组模拟链表很简单, 声明一个空中
于充分之勤组, 然后自数组的中游开始满怀多少, 这样干到移动多少常常,
只需要将后面的数码插在前头就是可.
这种措施缺点很鲜明, 就是占有空间或于坏, 但就解本题来说,
是完全可的.
第6栽, 如果必须界定只能用频繁组, 数组大小只能当n.
可以利用活动算法来贯彻, 这种艺术比较麻烦
知晓, 我当C语言网上看到有大牛实现了, 可以参照这里:
http://blog.csdn.net/xtzmm1215/article/details/38407799

第3栽实现方式, 控制打印顺序, 完整兑现代码:

#include <stdio.h>

int main () {
    int i;
    int n;
    int m;
    char ch = ' '; // 打印控制变量, 默认空格
    int arr[100];  // 下标0, 不存数据

    scanf("%d", &n);
    scanf("%d", &m);
    m = m % n; // 确保 m < n

    // 给数组赋值
    for (i=1; i<=n; i++) {
        scanf("%d", &arr[i]);
    }

    // 接下来分两次, 分别控制打印顺序
    // 第1次打印, 从倒数第m个数开始
    for (i=n-m+1; i<=n; i++) {
        printf("%d ", arr[i]);
    }

    // // 第2次打印, 从1到倒数第m个数
    for (i=1; i<=n-m; i++) {
        if (i == (n - m)) {
            ch = '\n';
        }
        printf("%d%c", arr[i], ch);
    }

    return 0;
}

链表实现

运链表实现, 根据题意至少需实现链表的插, 删除, 定位操作.
一般情况下, 大部分操作都是把链表后面的因素用到眼前,
如果真的求偶极致少之倒次数,
可添加判断标准, 从而有些情况用拿链表前面的要素移动到后面.
咱这里为简单, 插入只来2栽状况相同种植是在头插入一种是于尾部插入.
鉴于我们结构体只生一个数目域data,
所以在实行删除(在题目里面相当给活动)操作时, 只要
先保存着数据域的价, 就足以把欠节点彻底从链表中移除(free)

圆兑现代码:

#include <stdio.h>

struct list {
    int data;
    struct list *next;
};
typedef struct list s_list;
typedef struct list *p_list;

p_list insert (p_list p, int x);
void print (p_list head);
int del (p_list head, p_list *rear);


int main () {
    int i;
    int n;        // 链表元素个数
    int m;        // 右移位数
    int x;        // 当前读取的数
    p_list head;  // 头指针
    p_list rear;  // 尾指针

    head = (s_list*)malloc(sizeof(s_list));
    head->next = NULL;
    rear = head;
    scanf("%d", &n);
    scanf("%d", &m);
    m = m % n;

    // 为链表赋值
    for (i=1; i<=n; i++) {
        scanf("%d", &x);
        rear = insert(rear, x); // 动态修改尾指针的指向
    }

    // 对链表进行移动
    for (i=1; i<=m; i++) {
        x = del(head, &rear);
        insert(head, x);
    }
    print(head);

    return 0;
}

// 在p元素的后面插入一个元素x
// 返回值: 返回一个指向被删元素的指针
p_list insert (p_list p, int x) {
    p_list temp = (s_list*)malloc(sizeof(s_list));
    temp->data = x;
    temp->next = p->next;
    p->next = temp;
    return temp;
}

// 删除一个尾元素, 并返回其值
// 把链表元素的一个节点整个从程序中移除并无大碍, 只要被删元素
// 的值, 被保存下来, 以后随时可以重建被删节点
// 该函数需要在内部改变rear的指向, 因此需要定义指针的指针
int del (p_list head, p_list *rear) {
    p_list pre;      // 最后一个元素的前一个元素
    p_list tempRear; // 指向被删元素, 也就是最后一个元素
    int value;       // 被删除元素的值

    value = (*rear)->data; // 又是运算符优先级的坑
    tempRear = *rear;
    pre = head->next;
    while (pre->next != *rear) {
        pre = pre->next;
    }
    *rear = pre;
    (*rear)->next = NULL;
    free(tempRear);

    return value;
}

// 打印链表
void print (p_list head) {
    p_list p;
    char ch = ' '; // 打印控制变量

    p = head->next;
    while (p != NULL) {
        if (p->next == NULL) {
            ch = '\n';
        }
        printf("%d%c", p->data, ch);
        p = p->next;
    }
}