一:题目
(一)基础知识补充(RAID和奇偶校验)
奇偶校验(同行数据中同位上的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] == '\n')
{
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("\n");
}
主函数
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.\n",c++);
else
{
printf("Disk set %d is valid, contends are: ",c++);
printValidData();
}
}
freopen("CON", "r", stdin);
freopen("CON", "w", stdout);
}