实现QQ新帐户申请和老帐户登陆的简化版功能。最大挑战是:据说现在的QQ号码已经有10位数了。
输入格式:
输入首先给出一个正整数N(≤10^5),随后给出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 myQQ@qq.com
N 1234567890 myQQ@qq.com
N 1234567890 myQQ@qq.com
L 1234567890 myQQ@qq
L 1234567890 myQQ@qq.com
输出样例:
ERROR: Not Exist
New: OK
ERROR: Exist
ERROR: Wrong PW
Login: OK
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define KEYLENGTH 17/* 关键词字符串的最大长度*/
#define MAXTABLESIZE 100000
#define MAXD 5
typedef char ElementType[KEYLENGTH]; /* 关键词类型用字符串*/
typedef int Index; /* 散列地址类型*/
typedef struct LNode *PtrToLNode;
struct LNode
{
ElementType Data;
ElementType PW;
PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;
typedef struct TblNode *HashTable;
struct TblNode
{ /* 散列表结点定义*/
int TableSize; /* 表的最大长度*/
List Heads; /* 指向链表头结点的数组*/
};
HashTable CreateTable( int TableSize);
void Insert( HashTable H, char C, ElementType Key1, ElementType Key2 );
void DestroyTable( HashTable H );
int main()
{
int N, i;
char C;
ElementType Key1, Key2;
HashTable H;
scanf("%d", &N);
H = CreateTable(N); /* 创建一个散列表*/
for(i=0; i<N; i++)
{
char ch = getchar(); //消除输入时回车的影响
scanf("%c%s%s", &C, Key1, Key2);
Insert( H, C, Key1, Key2 );
}
DestroyTable( H );
return 0;
}
int NextPrime( int N )
{ /* 返回大于N且不超过MAXTABLESIZE的最小素数*/
int i, p = (N%2)? N+2 : N+1; /*从大于N的下一个奇数开始*/
while( p <= MAXTABLESIZE )
{
for( i=(int)sqrt(p); i>2; i--)
if( !(p%i) ) break; /* p不是素数*/
if( i==2 ) break; /* for正常结束,说明p是素数*/
else p += 2; /* 否则试探下一个奇数*/
}
return p;
}
HashTable CreateTable( int TableSize)
{
HashTable H;
int i;
H = (HashTable)malloc(sizeof(struct TblNode));
H->TableSize= NextPrime(TableSize);
H->Heads = (List)malloc(H->TableSize*sizeof(struct LNode));
for( i=0; i<H->TableSize; i++ )
{
H->Heads[i].Data[0] = '\0';
H->Heads[i].PW[0] = '\0';
H->Heads[i].Next= NULL;
}
return H;
}
int Hash( ElementType Key, int P )
{ /* 除留余数法法散列函数*/
int index = 0;
for( int i = 0; i < MAXD; i++ )
index = index * 10 + Key[i] - '0';
return (index % P);
}
Position Find( HashTable H, ElementType Key )
{
Position P;
Index Pos;
/* 初始散列位置*/
Pos = Hash(Key, H->TableSize);
P = H->Heads[Pos].Next; /* 从该链表的第1个结点开始*/
/* 当未到表尾,并且Key未找到时*/
while( P && strcmp(P->Data, Key) ) P = P->Next;
return P; /* 此时P或者指向找到的结点,或者为NULL */
}
void Insert( HashTable H, char C, ElementType Key1, ElementType Key2 )
{
Position P, NewCell;
Index Pos;
P = Find( H, Key1 );
if(!P && C == 'N')
{ /* 关键词未找到,可以插入*/
NewCell= (Position)malloc(sizeof(struct LNode));
strcpy(NewCell->Data, Key1); /* 初始散列位置*/
strcpy(NewCell->PW, Key2);
Pos = Hash(Key1, H->TableSize); /* 将NewCell插入为H->Heads[Pos]链表的第1个结点*/
NewCell->Next = H->Heads[Pos].Next;
H->Heads[Pos].Next= NewCell;
printf("New: OK\n");
}
else if( !P && C == 'L')printf("ERROR: Not Exist\n");
else if( P && C == 'N')printf("ERROR: Exist\n");
else if( P && C == 'L')
{
if( !strcmp(P->PW, Key2) )
printf("Login: OK\n");
else
printf("ERROR: Wrong PW\n");
}
}
void DestroyTable( HashTable H )
{
int i;
Position P, Tmp;
/* 释放每个链表的结点 */
for( i=0; i<H->TableSize; i++ )
{
P = H->Heads[i].Next;
while( P )
{
Tmp = P->Next;
free( P );
P = Tmp;
}
}
free( H->Heads ); /* 释放头结点数组 */
free( H ); /* 释放散列表结点 */
}