一:題目
(一)基礎知識補充(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);
}