11-散列3 QQ帐户的申请与登陆(浙大数据结构PTA习题)

11-散列3 QQ帐户的申请与登陆        分数 25        作者 DS课程组        单位 浙江大学

题目:

实现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 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

代码长度限制:16 KB        时间限制:1200 ms        内存限制:64 MB

题目解析:

本题本质考察对哈希表的查询与插入。在这里采用除留取余法构造散列函数,使用分离链接法解决散列冲突,关于分离链接法的理解如下图所示(图片来源于慕课浙大数据结构)。

 此外,该题还需对哈希表查询或插入结果的多种情况进行讨论,以及对字符串的一些基本处理。

参考代码:

// 使用分离链表法 
# include<stdio.h>
# include<stdlib.h>
# include<string.h>
# include<math.h>

# define TABLESIZE 100000	// 表长 
# define MAXNAME 10			// 账号最大长度 
# define PASSWORD 16		// 密码最大长度 
# define HAVE 1				// 创建时账号已存在 
# define NOTEXIST 2			// 登录时账号不存在 
# define WRONGPW 3			// 登录时密码错误 
# define OK 4				// 登录或注册成功 

// 结点的结构
struct Node{
    char Name[MAXNAME+1];
    char Password[PASSWORD+1];
    struct Node* Next; 
};
typedef struct Node* PtrToNode;

// 采用分离链表法存储散列表
struct Table{
    int Length;          // 散列表的长度
    PtrToNode* Array;    // 散列表的数组
};
typedef struct Table* PtrToTable;

PtrToTable CreateTable();
int Hash(char Name[]); 
int InsertTable(PtrToTable H, char Name[], char Password[]); 
int Login(PtrToTable H, char Name[],char Password[]);

int main(){
	// 指令条数
    int N;
    scanf("%d",&N);
    int i;
    // 创建一个散列表
    PtrToTable H = CreateTable(); 
    char Command[2],Name[MAXNAME+1],Password[PASSWORD+1];
    for(i=0;i<N;i++){
        scanf("%s",Command);
        scanf("%s",Name);
        scanf("%s",Password);
        if(Command[0]=='N'){
            // 创建新用户
            int IRes = InsertTable(H,Name,Password);
            if(IRes==HAVE)printf("ERROR: Exist\n");
			else if(IRes==OK)printf("New: OK\n"); 
        }else if(Command[0]=='L'){
            // 登录
            int LRes = Login(H,Name,Password);
            if(LRes == NOTEXIST)printf("ERROR: Not Exist\n");
            else if(LRes == WRONGPW)printf("ERROR: Wrong PW\n");
            else if(LRes == OK)printf("Login: OK\n");
        }
    }
	return 0;
}

// 创建并初始化一个散列表
PtrToTable CreateTable(){
    PtrToTable H = (PtrToTable)malloc(sizeof(struct Table));
    H->Length = TABLESIZE;
    H->Array = (PtrToNode*)malloc(sizeof(PtrToNode)*H->Length);
    // 每个位置处设置一个空表头 
    int i;
    for(i=0;i<H->Length;i++){
        PtrToNode New = (PtrToNode)malloc(sizeof(struct Node));
        New->Next = NULL;
        H->Array[i] = New;
    }
    return H;
}

// 散列函数 
int Hash(char Name[]){
    // 因为QQ号码最小为1001,因此最多只能利用前面4位 
    int i,res = 0;
    for(i=0;i<=3;i++){
        res = 10*res + Name[i] - '0';
    }
    res = res*(Name[3]-'0') % TABLESIZE;
    return res;
}

// 用户登录 
int Login(PtrToTable H, char Name[],char Password[]){
	// 获取键值
	int Key = Hash(Name);
	// 跳过空表头 
	PtrToNode Tmp = H->Array[Key]->Next;
	while(Tmp!=NULL){
		if(strcmp(Tmp->Name, Name)==0){
			// 账号匹配成功
			if(strcmp(Tmp->Password,Password)==0){
				// 账号密码均匹配成功,登录成功 
				return OK; 
			}else{
				// 账号存在,但密码匹配失败 
				return WRONGPW;
			}
		}
		Tmp = Tmp->Next;
	}
	// 账号未匹配上
	return NOTEXIST; 
}

// 用户注册 
int InsertTable(PtrToTable H, char Name[], char Password[]){
	// 获取键值
	int Key = Hash(Name);
	PtrToNode Last = H->Array[Key];
	PtrToNode Tmp = Last -> Next;
	while(Tmp!=NULL){
		if(strcmp(Tmp->Name, Name) == 0){
			// 账号已经存在
			return HAVE; 
		}
		Last = Tmp;
		Tmp = Tmp->Next;	
	}
	// 在while中没有结束说明不存在,则进行插入
	PtrToNode New = (PtrToNode)malloc(sizeof(struct Node));
	strcpy(New->Name, Name);
	strcpy(New->Password,Password);
	Last->Next = New;
	New->Next = Tmp;
	// 插入成功 
	return OK; 
}

运行结果:

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值