zoukankan      html  css  js  c++  java
  • 算法习题---4-7RAID技术(UV509)

    一:题目

    (一)基础知识补充(RAID和奇偶校验)

    磁盘管理—磁盘阵列(RAID)实例详解(本题目常用RAID 5技术实现)

    奇偶校验(同行数据中同位上的1的个数,偶校验时:1的个数为偶数则校验结果为0,否则为1,奇校验时相反:1的个数为偶数则校验结果为1,否则为0)

    (二)题目详解

    RAID技术用多个磁盘保存数据。每份数据在不止一个磁盘上保存,因此在某个磁盘损 
    坏时能通过其他磁盘恢复数据。本题讨论其中一种RAID技术。数据被划分成大小 
    为s(1≤s≤64)比特的数据块保存在d(2≤d≤6)个磁盘上,如图所示,每d-1个数据块都 
    有一个校验块,使得每d个数据块的异或结果为全0(偶校验)或者全1(奇校验)。

    (三)案例解析

    例如,d=5,s=2,偶校验,数据6C7A79EDFC(二进制01101100 01111010 01111001 11101101 11111100)的保存方式如图所示

    其中加粗块是校验块。输入d、s、b、校验的种类(E表示偶校验,O表示奇校验)以及b(1≤b≤100)个数据块(其中“x”表示损坏的数据),
    你的任务是恢复并输出完整的数据。如果校验错或者由于损坏数据过多无法恢复,应报告磁盘非法。

    (四)样例输入

    注意:

    其中样例输入中:第一组数据网站和书籍有所出入。自己检查后发现书上是可以的。所以将原来的
    0001011111 
    0110111011 
    1011011111 
    1110101100 
    0010010111 
    替换为:
    0001101100
    0110111010
    0111011001
    1110111101
    1111110011

    样例输入:

    5 2 5  //第一个参数是磁盘块(将一个数据块拆分为多个分别存放在各个磁盘块中)--列数  第二个参数是每个磁盘块存放的数据位数  第三个参数是数据块数(将每一块数据拆分为多个分别存放在各个磁盘中)--行数
    E     //E是偶校验 O是奇校验
    0001101100
    0110111010
    0111011001
    1110111101
    1111110011
    3 2 5
    E
    0001111111
    0111111011
    xx11011111
    3 5 1
    O
    11111
    11xxx
    x1111
    0  //0代表输入结束

    注意点:

    1、校验块是不加入十六进制运算的 
    2、校验块的顺序是第一行的第一块,第二行的第二个,到了某行最后一个时,下一行就有从第一个开始算做校验块  -----  当前行数%列数
    3、十六进制转换是 一个十六进制数字需要四个二进制数字,所以每四位二进制就是一位十六进制 
    4校验进行是一行中每个块的相同位进行校验 
    5、奇校验就是每个数互相异或下来是1,偶校验就是0 
    6、磁盘不合理有三种可能性:一是已知的位校验不符合,二是未知位有多位,无法判断其内容,三是校验位中含有x

    数据实际存放样式:

    5 2 5
    E
    0001101100            00 01 10 11 00
    0110111010            01 10 11 10 10
    0111011001    ----->  01 11 01 10 01
    1110111101            11 10 11 11 01
    1111110011            11 11 11 00 11
    3 2 5
    E                    00 01 11
    0001111111           11 11 01
    0111111011 ---->     11 11 10
    xx11011111           11 xx 11
                         01 11 11
    3 5 1
    O
    11111    
    11xxx        ----->    11111 11xxx x1111
    x1111

    (五)样例输出

    Disk set 1 is valid, contents are: 6C7A79EDFC 
    Disk set 2 is invalid. 
    Disk set 3 is valid, contents are: FFC

    二:代码实现

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <stdlib.h>
    #include <string>
    
    #define ROW 100    //最多100条    100行
    #define COL 6    //最多6个磁盘 6列
    #define BITS 64    //每个磁盘块最多64位
    
    int col, row, bits;
    char DISK[ROW][COL][BITS], ct;    //获取基本数据:磁盘数据和校验类型
    char Ddata[COL][BITS], CkCode[BITS];    //获取每行数据和校验值
    
    //-1无效 0结束 1正确
    

    获取磁盘数据,并进行检测和纠错

    int getDiskData()    //改进:在这里检错
    {
        int flag = 1;
        int x_bits[BITS], xNum = 0, OneNum[BITS];    //记录x位置x_bits中内容是对于列数值和x的个数
        scanf("%d", &col);
        if (col == 0) return 0;
        scanf("%d %d", &bits, &row);
        getchar();
        scanf("%c", &ct);
        getchar();
    
        //获取磁盘数据
        for (int i = 0; i < row;i++)
        {
            memset(x_bits, -1, sizeof(x_bits));
            memset(OneNum, 0, sizeof(OneNum));
            for (int j = 0; j < col; j++)
            {
                for (int k = 0; k < bits; k++)
                {
                    scanf("%c", &DISK[i][j][k]);
                    if (DISK[i][j][k] == '
    ')
                    {
                        k--;
                        continue;
                    }
                    if (i%col == j)    //不允许校验位为x
                    {
                        if (DISK[i][j][k] == 'x')
                            flag = -1;
                    }
    
                    if (DISK[i][j][k] == 'x')
                    {
                        if (x_bits[k] != -1)    //不允许在同一位出现多个x
                            flag = -1;
                        x_bits[k] = j;    //最多记录不同位上的x位置
                    }
                    if (i%col !=j && DISK[i][j][k] == '1')
                        OneNum[k]++;
                }
            }
            //复制校验位
            memcpy(CkCode, DISK[i][i%col], BITS);
            for (int k = 0; k < bits;k++)    //将对应位置上的数据进行纠错
            {
                if (x_bits[k] != -1)    //该行有x数据,需要纠错(纠错就避免了检错)
                {
                    if (ct == 'E')    //偶校验
                    {
                        if ((CkCode[k] == '0'&&OneNum[k] % 2 == 1) || (CkCode[k] == '1' && OneNum[k] % 2 == 0))
                            DISK[i][x_bits[k]][k] = '1';
                        else
                            DISK[i][x_bits[k]][k] = '0';
                    }
                    else    //奇校验
                    {
                        if ((CkCode[k] == '1'&&OneNum[k] % 2 == 1) || (CkCode[k] == '0' && OneNum[k] % 2 == 0))
                            DISK[i][x_bits[k]][k] = '1';
                        else
                            DISK[i][x_bits[k]][k] = '0';
                    }
                }
                else    //该行没有x数据,直接检错
                {
                    if (ct == 'E' && ((CkCode[k] == '1'&&OneNum[k] % 2 == 0) || (CkCode[k] == '0' && OneNum[k] % 2 == 1)))
                        flag = -1;
                    if (ct == 'O' && ((CkCode[k] == '1'&&OneNum[k] % 2 == 1) || (CkCode[k] == '0' && OneNum[k] % 2 == 0)))
                        flag = -1;
                }
            }
        }
        getchar();
        return flag;
    }

    将字符串二进制转为16进制输出

    //转换16进制输出
    void printValidData()
    {
        int n = 0;
        int m;
        //获取每一行数据,进行输出
        for (int i = 0; i < row; i++)
        {
            m = 0;
            for (int j = 0; j < col; j++)
            {
                if (i%col==j) continue;    //跳过校验位
                for (int k = 0; k < bits; k++)
                {
                    if (DISK[i][j][k] == '1')
                        n |= 0x01;
                    else
                        n |= 0x00;
                    m++;
                    if (m == 4)
                    {
                        printf("%X", n);
                        n = 0, m = 0;
                    }
                    n <<= 1;
                }
            }
            //获取完一行
            if (m > 0 && m != 4)
            {
                m++;
                while (m != 4)
                {
                    n |= 0x00,n <<= 1;
                    m++;
                }
                printf("%X", n);
            }
        }
        printf("
    ");
    }

    主函数

    void main()
    {
        int c = 1, flag;
        FILE* fp = freopen("data7.in", "r", stdin);
        freopen("data7.out", "w", stdout);
    
        while (!feof(fp))
        {
            flag = getDiskData();
            if (flag == 0) break;
            if (flag == -1)
                printf("Disk set %d is invalid.
    ",c++);
            else 
            {
                printf("Disk set %d is valid, contends are: ",c++);
                printValidData();
            }
        }
    
        freopen("CON", "r", stdin);
        freopen("CON", "w", stdout);
    }
  • 相关阅读:
    从运维角度看中大型网站架构的演变之路
    <经验杂谈>Mysql中字符串处理的几种处理方法concat、concat_ws、group_concat
    <经验杂谈>C#使用AES加密解密的简单介绍
    <经验杂谈>C#对CA证书加密解密的简单介绍
    C#实现HttpUtility.UrlEncode输出大写字母
    <微信应用开发系列>定时刷新AccessToken
    <经验杂谈>C#/.Net字符串操作方法小结
    <经验杂谈>查询表结构的SQL语句
    如何在.Net中使用Redis
    ASP.NET MVC进阶之路:深入理解Controller激活机制并使用Ioc容器创建对象
  • 原文地址:https://www.cnblogs.com/ssyfj/p/11162287.html
Copyright © 2011-2022 走看看