QQ新規アカウント申請と旧アカウントログインの簡易版機能を実現。最大の課題は、現在の QQ 番号はすでに 10 桁であると言われています。
入力形式:
入力は最初に正の整数 N (≤105) を与え、その後に N 行の命令が続きます。各コマンドラインの形式は、「コマンド文字 (スペース) QQ 番号 (スペース) パスワード」です。コマンド記号が "N" (New を表す) の場合は、新しい QQ アカウントを申請し、その後に新しいアカウントの番号とパスワードを入力することを意味し、コマンド記号が "L" (Login を表す) の場合はログインを意味します。古いアカウントで入力し、その後にログイン情報を入力します。QQ番号は、10桁以下で1000を超える整数である(QQボスの番号は1001と言われている)。パスワードは、スペースを含まない 6 文字以上 16 文字以下の文字列である必要があります。
出力フォーマット:
各コマンドについて、対応する情報を指定します。
1) 新しく適用されたアカウントが成功した場合、「New: OK」を出力します。
2) 新しく適用された番号がすでに存在する場合、「ERROR: Exist」を出力します。
3) 古いアカウントのログインが成功した場合、「Login: OK」を出力します。 ;
4) 古いアカウントの QQ 番号が存在しない場合は、「ERROR: Not Exist」が出力されます;
5) 古いアカウントのパスワードが間違っている場合は、「ERROR: Wrong PW」が出力されます。
入力サンプル:
5
L 1234567890 [email protected]
N 1234567890 [email protected]
N 1234567890 [email protected]
L 1234567890 myQQ@qq
L 1234567890 [email protected]
出力例:
ERROR: Not Exist
New: OK
ERROR: Exist
ERROR: Wrong PW
Login: OK
参照コード:
/**
* 7-11 QQ帐户的申请与登陆
* 哈希表 分离链接法
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
/*账号与密码最大长度的定义
它们的最大长度需要比题目所给的大一位
这是因为还需要一个位置来储存'\0'来判断字符串的结尾*/
#define Max_Password_Len 17
#define Max_Account_Len 11
#define MaxTableSize 1000000
/*各种状态的定义
最好用正数表示成功的状态
用负数或0表示失败的状态
这样会让强迫症看了舒服一点*/
#define ERROR_WrongPW -2
#define ERROR_Exist -1
#define ERROR_NOTExist 0
#define New_OK 1
#define Login_OK 2
typedef char AccountType[Max_Account_Len];//账号类型定义
typedef char PasswordType[Max_Password_Len];//密码类型定义
typedef int Index;
typedef enum {
New, Log
} Pattern;//两种模式,新建账号与登入账号
typedef struct {
AccountType Account;
PasswordType Password;
} ElemType;//数据类型的定义,每个对应一个用户,内含用户的账号和密码
//链表指针的定义
typedef struct LNode *PtrToLNode;
//链表结点的定义
typedef struct LNode {
PtrToLNode Next;
ElemType Data;
} LNode;
typedef PtrToLNode List;//链表的定义
typedef PtrToLNode Position;//哈希表中结点位置的定义
//哈希表的定义
typedef struct TblNode *HashTable;
typedef struct TblNode {
int TableSize;//哈希表的大小
List Heads;//储存各个列表头节点的数组
} TblNode;
int NextPrime(int N)//返回N的下一个素数
{
int i, P;
P = N % 2 ? N + 2 : N + 1;
//P为N之后的第一个奇数
while (P < MaxTableSize) {
for (i = (int) sqrt(P); i > 2; i--)//因为只考虑奇数,所以i为2时就结束了
if (P % i == 0)
break;
if (i == 2)
break;//i为2说明P为素数
else
P += 2;//i!=2说明P不是素数,则P指向下一个奇数
}
return P;
}
int Hash(int Key, int TableSize) {//返回Key值相对应的哈希值,即其在哈希表中的储存下标
return Key % TableSize;
}
HashTable CreateTable(int TableSize) { //构造空的哈希表
HashTable H;
int i;
H = (HashTable) malloc(sizeof(TblNode));
H->TableSize = NextPrime(TableSize);
H->Heads = (List) malloc(sizeof(LNode) * H->TableSize);
for (i = 0; i < H->TableSize; i++) {
H->Heads[i].Data.Account[0] = '\0';
H->Heads[i].Data.Password[0] = '\0';
H->Heads[i].Next = NULL;
}
return H;
}
Position Find(HashTable H, ElemType Key) {
Position Pos;
Index p;
if (strlen(Key.Account) > 5) //账号大于5位时取最后5位
p = Hash(atoi(Key.Account +
strlen(Key.Account) - 5), H->TableSize);
else//账号不大于5位则等于它本身
p = Hash(atoi(Key.Account), H->TableSize);
Pos = H->Heads[p].Next;
while (Pos && strcmp(Key.Account, Pos->Data.Account))
Pos = Pos->Next;
return Pos;//Pos指向用户数据的位置,没有注册就返回NULL
}
int NewOrLog(HashTable H, ElemType Key, Pattern P) { //返回状态参数
Position Pos, NewPos;
Index p;
Pos = Find(H, Key);
switch (P) {
case Log:
if (Pos == NULL)
return ERROR_NOTExist;//登陆时不存在账号
else if (strcmp(Pos->Data.Password, Key.Password) ||
(strlen(Key.Password) > 16 || strlen(Key.Password) < 6))
return ERROR_WrongPW; //密码错误或格式错误
else
return Login_OK;//账号和密码均正确,可以登录
case New:
if (Pos != NULL)
return ERROR_Exist; //新建账号时发现已经存在这样的账号了
else {
NewPos = (Position) malloc(sizeof(LNode));
strcpy(NewPos->Data.Account, Key.Account);
strcpy(NewPos->Data.Password, Key.Password);
if (strlen(Key.Account) > 5)
p = Hash(atoi(Key.Account +
strlen(Key.Account) - 5), H->TableSize);
else
p = Hash(atoi(Key.Account), H->TableSize);
NewPos->Next = H->Heads[p].Next;
H->Heads[p].Next = NewPos;
return New_OK; //插入新值并返回插入成功
}
}
}
void DestroyTable(HashTable H) { //销毁哈希表
PtrToLNode p, q;
int i;
for (i = 0; i < H->TableSize; i++) {
q = H->Heads[i].Next;
while (q) {
p = q->Next;
free(q);
q = p;
}
}
free(H);
}
int main(void) {
int N, i;
ElemType Key;
char Input;
Pattern P;
HashTable H;
scanf("%d", &N);
H = CreateTable(2 * N);
for (i = 0; i < N; i++) {
scanf("\n%c %s %s", &Input, Key.Account, Key.Password);
P = (Input == 'L') ? Log : New;
switch (NewOrLog(H, Key, P)) {//最后根据不同返回值输出对应状态即可
case ERROR_Exist:
printf("ERROR: Exist\n");
break;
case ERROR_NOTExist:
printf("ERROR: Not Exist\n");
break;
case ERROR_WrongPW:
printf("ERROR: Wrong PW\n");
break;
case Login_OK:
printf("Login: OK\n");
break;
case New_OK:
printf("New: OK\n");
break;
}
}
DestroyTable(H);
return 0;
}