zoukankan      html  css  js  c++  java
  • 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. 可以利用移位算法来实现, 这种方法比较难
    理解, 我在网上看到有大牛实现了, 可以参考这里:
    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 = '
    ';
            }
            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 = '
    ';
            }
            printf("%d%c", p->data, ch);
            p = p->next;
        }
    }
    
    
  • 相关阅读:
    Android 图片的缩略图
    Android 非Activity类引用getResources()方法问题的解决方法
    Android 广播(内部类)
    Android 消息广播Intent传递数据
    Android 防止按钮连续点击的方法(Button,ImageButton等)
    Android 广播机制(两种注册方法)与中断广播
    Android 使用意图传递数据
    Android 使用全局变量传递数据
    Android 使用剪切板传递数据
    android 使用静态变量传递数据
  • 原文地址:https://www.cnblogs.com/asheng2016/p/7661311.html
Copyright © 2011-2022 走看看