为什么我的哈希程序没有通过测试

Why does my hashing program fail the tests

任务:
要在系统中注册,每个居民都必须提供一个密码。密码由拉丁字母(大写和小写)以及0到9的数字组成,即总共可以使用62个字符。密码长度为 5 到 20 个字符。密码以加密形式存储在数据库中,按照以下算法进行加密:

  1. 统计大写拉丁字母的个数b。对于密码中的每个大写字母字符,循环右移 bb 个字符(例如,如果 b=3,则 D 字符转换为 G 字符,Y 字符转换为 B 字符)。
  2. 同样,对于密码中的每个小写字符,循环右移m个字符,其中m是密码中小写字母的个数。

为了在数据库中快速搜索用户,使用以下算法为每个加密密码计算哈希函数:

  1. 所有62个字符都是有序的,数字在前,然后是小写字母,然后是大写字母。
  2. 每个字符都分配了一个代码 - 该序列中字符的编号,从 0 开始。因此,数字代码与其值匹配,小写字母代码 a-10、b-11 等。
  3. 所有代码求和,求和s除以数p和q的余数。得到的一对数字 (smodp,smodq) 将是哈希函数的值。

如果碰撞很少发生,即哈希函数的值匹配不同的密码,则认为哈希函数是好的。

约翰想出了一个新密码。同时,数据库中已经有nn个密码,想避免冲突。约翰会成功吗?

输入数据

第一行包含一个字符串,表示 John 的密码。 第二行包含一个整数 n——数据库中密码的数量。 第三行包含整数 p 和 q。以下行以未加密的形式存储密码。

输出数据

一个整数是散列函数与约翰密码的散列函数匹配的密码的个数。

示例输入:
AabB1cd
5
13 17
Nik143pasw
qeAom1
q1w2e3r4t
aBoba2012
N33iEj

示例输出:
2

注:
与 John 的哈希函数匹配的密码会突出显示。

处理约翰的密码: 循环移位后:CefD1gh(大写字母移位2,小写字母移位4) 字符编码之和为38+14+15+39+1+16+17=140 哈希函数等于 (10,4)

您的代码中存在一些逻辑问题。当您将大写和小写字符旋转为它们的“加密”形式时,您将遍历密码两次,有时会错误地旋转字符。仅以行

为例
if (pas[i] + big >= 'A' && pas[i] + big <= 'Z') pas[i] = pas[i] + big;

考虑 pas[i] == '9'big == 8 的情况。您最终会将所有 9 转换为 A

现在考虑下一个循环中的行

if (pas[i] + small >= 'a' && pas[i] + small <= 'z') pas[i] = pas[i] + small;

如果 small 足够大,它将类似地将一些大写字母转换为小写字母。

你也可以把这两个问题结合起来。考虑 pas[i] 原来是 Ybig 是 1,little 是 7 的情况。你将变换 Y --> Z,然后在下一步变换Z --> a.

  1. 将您的单个大型主要功能划分并抽象为较小的功能块。这将允许您单独推理每个部分,而不是试图将整个 main() 留在脑海中。人类的短期记忆是有限的。

一些建议的功能包括

  • bool is_upper(char c)
  • bool is_lower(char c)
  • bool is_numeric(char c)
  • char rotate_upper(char c, int steps)
  • char rotate_lower(char c, int steps)
  1. 与其在转换步骤中遍历密码两次,不如考虑遍历密码一次。如果字符是大写的,则进行相应的转换。如果是小写,则进行相应的转换。这将防止您重复旋转某些数字。

结合以上所有内容,您的主要功能的两个加密循环可以从:

for (int i = 0; i < pas.length(); i++)
    {
        if (pas[i] + big >= 'A' && pas[i] + big <= 'Z') pas[i] = pas[i] + big;
        else if (pas[i] >= 'A' && pas[i] <= 'Z') {
            int tempVar = big;
            while (tempVar > 0) {
                if (pas[i] == 'Z') {
                    pas[i] = 'A';
                    tempVar = tempVar - 1;
                }
                tempVar = tempVar - 1;
                pas[i] = pas[i] + 1;
            }
        }
    }
    for (int i = 0; i < pas.length(); i++)
    {
        if (pas[i] + small >= 'a' && pas[i] + small <= 'z') pas[i] = pas[i] + small;
        else if (pas[i] >= 'a' && pas[i] <= 'z') {
            int tempVar = small;
            while (tempVar > 0) {
                if (pas[i] == 'z') {
                    pas[i] = 'a';
                    tempVar = tempVar - 1;
                }
                pas[i] = pas[i] + 1;
                tempVar = tempVar - 1;
            }
        }
    }

for (int i = 0; i < pas.length(); i++) {
    char c = pas[i];
    if (is_upper(c)) {
        pas[i] = rotate_upper(c, big);
    }
    else if (is_lower(c)) {
        pas[i] = rotate_lower(c, small);
    }
}

您可以将 30 行代码转换为不到 10 行。这对于您、开发人员和任何潜在的审阅者来说都更容易阅读。