PTA QQ帐户的申请与登陆 思路分析及代码解析

一、前导

1. 需要掌握的知识

通过开放地址法实现Hash/哈希表

2. 题目信息

2.1 题目来源:PTA / 拼题A
2.2 题目地址: QQ帐户的申请与登陆

二、解题思路分析

1. 题意理解

对输入的数据进行判定(L代表登录, N代表新建),打印对应的判定结果。举个栗子:L 1234567890 myQQ@qq.com ,由于数据库中还没有账号1234567890 ,因此打印 ERROR: Not Exist

1. 1 输入数据

5 //条数
L 1234567890 myQQ@qq.com //指令 QQ号 对应密码
N 1234567890 myQQ@qq.com
N 1234567890 myQQ@qq.com
L 1234567890 myQQ@qq
L 1234567890 myQQ@qq.com

1.2 输出数据

ERROR: Not Exist //对应的结果
New: OK
ERROR: Exist
ERROR: Wrong PW
Login: OK
......

2. 思路分析

2.1 由于是字符型数据(账号、密码),优先使用Hash表存储和查询
2.2 首先创建Hash表(开放地址),遇到L就执行查询、遇到N就执行插入,根据查询、插入的结果打印对应的判定语句

三、具体实现

1. 弯路和bug

1.1 Hash表编码的熟练度仍然偏低,只能多练习啦
1.2 C语言中没有string类,用malloc无法识别,编译时会报:读取字符串的字符出错
1.3 别忘记释放Hash表占用的内存

2. 代码框架

2.1 采用的数据结构

结构体

#define Size 17 //QQ密码最大16位+'\0'=17位

typedef char ElementType[Size]; //用于存储账号和密码
typedef int Position;
typedef enum {Occupied,Vacant} PostionStatus;

struct HashTableCell
{
	ElementType UserNumber;
	ElementType Password;
	PostionStatus Status;
};
typedef struct HashTableCell Cell;

struct HashTableStructure
{
	int HashTableSize;
	Cell* CellArray;
};
typedef HashTableStructure* HashTable;

2.2 程序主体框架

               程序伪码描述
int main()
{
	1.创建Hash表(开发地址)
	2.读入数据、执行对应的操作
}

2.3 各分支函数

2.3.1 CreateHashTable( ) 创建Hash表并赋初值(开放地址法)

HashTable CreateHashTable(int TableSize)
{
	HashTable H;
	H = (HashTable)malloc(sizeof(struct HashTableStructure));

	H->HashTableSize = NextPrime(TableSize);

	H->CellArray = (Cell*)malloc(sizeof(Cell) * H->HashTableSize);

	for (int i = 0; i < H->HashTableSize; i++)
	{
		H->CellArray[i].Status = Vacant;
		H->CellArray[i].Password[0] = '\0';
		H->CellArray[i].UserNumber[0] = '\0';
	}

	return H;
}

2.3.2 Find( ) 在Hash表中搜索元素UserNumber,返回具体的位置,解决冲突的办法是线性探测法(代码易实现但效率低)

Position Find(HashTable H, ElementType UserNumber)
{
	Position Pos;
	Pos = Hash(UserNumber, H);

	while(H->CellArray[Pos].Status != Vacant && strcmp(H->CellArray[Pos].UserNumber, UserNumber) ) //当前位置非空 且 非目标账号就会一直循环
	{
		Pos++;//开放地址
		if (Pos > H->HashTableSize)
			Pos = Pos % H->HashTableSize;	
	}

	return Pos;
}

2.3.3 Insert( ) 在Hash表中插入账号信息和密码信息,若插入失败,则返回fasle

bool Insert(HashTable H, ElementType UserNumber, ElementType Password)
{
	Position Pos;
	Pos = Find(H, UserNumber);

	if (H->CellArray[Pos].Status == Vacant)
	{
		strcpy(H->CellArray[Pos].UserNumber, UserNumber);
		strcpy(H->CellArray[Pos].Password, Password);
		H->CellArray[Pos].Status = Occupied;
		return true;
	}
	else
		return false;
		
}

3. 完整AC编码

如有建议或问题,欢迎留言

#include <iostream>
#include <cmath>
#include <cstdlib>
#include <cstring>
using namespace std;

#define MAX 1000000
#define Size 17

typedef char ElementType[Size];
typedef int Position;
typedef enum {Occupied,Vacant} PostionStatus;

struct HashTableCell
{
	ElementType UserNumber;
	ElementType Password;
	PostionStatus Status;
};
typedef struct HashTableCell Cell;

struct HashTableStructure
{
	int HashTableSize;
	Cell* CellArray;
};
typedef HashTableStructure* HashTable;

HashTable CreateHashTable(int TableSize);
int NextPrime(int n);
Position Find(HashTable H, ElementType UserNumber);
bool Insert(HashTable H, ElementType UserNumber, ElementType Password);
Position Hash(ElementType UserNumber, HashTable T);
void DestoryHashTable(HashTable H);


int main()
{
	int Number;
	cin >> Number;

	char Action;
	ElementType UserNumber;
	ElementType Password;
	Position Pos;

	HashTable H;
	H = CreateHashTable(Number);

	for (int i = 0; i < Number; i++)
	{
		cin >> Action >> UserNumber >> Password;

		if (Action == 'L') //Login
		{
			Pos = Find(H, UserNumber);

			if (H->CellArray[Pos].Status == Vacant) //user not exist
				cout << "ERROR: Not Exist"<<endl; 
			else //user exist
			{
				if (!strcmp(H->CellArray[Pos].Password,Password)) //pw is right
					cout << "Login: OK"<<endl;
				else //pw is wrong
					cout << "ERROR: Wrong PW" << endl;
			}
		}
		else //Create a Account
		{
			if (Insert(H, UserNumber,Password))
				cout << "New: OK" << endl;
			else
				cout << "ERROR: Exist" << endl;

		}
	}

	DestoryHashTable(H);

	return 0;
}


bool Insert(HashTable H, ElementType UserNumber, ElementType Password)
{
	Position Pos;
	Pos = Find(H, UserNumber);

	if (H->CellArray[Pos].Status == Vacant)
	{
		strcpy(H->CellArray[Pos].UserNumber, UserNumber);
		strcpy(H->CellArray[Pos].Password, Password);
		H->CellArray[Pos].Status = Occupied;
		return true;
	}
	else
		return false;
		
}

Position Hash(ElementType UserNumber, HashTable H)
{
	int Number = atoi(UserNumber);
	return Number % H->HashTableSize;
}

Position Find(HashTable H, ElementType UserNumber)
{
	Position Pos;
	Pos = Hash(UserNumber, H);

	while(H->CellArray[Pos].Status != Vacant && strcmp(H->CellArray[Pos].UserNumber, UserNumber) )
	{
		Pos++;
		if (Pos > H->HashTableSize)
			Pos = Pos % H->HashTableSize;		
	}

	return Pos;
}

void DestoryHashTable(HashTable H)
{
	free(H->CellArray);
	free(H);
}

HashTable CreateHashTable(int TableSize)
{
	HashTable H;
	H = (HashTable)malloc(sizeof(struct HashTableStructure));

	H->HashTableSize = NextPrime(TableSize);

	H->CellArray = (Cell*)malloc(sizeof(Cell) * H->HashTableSize);

	for (int i = 0; i < H->HashTableSize; i++)
	{
		H->CellArray[i].Status = Vacant;
		H->CellArray[i].Password[0] = '\0';
		H->CellArray[i].UserNumber[0] = '\0';
	}

	return H;
}

int NextPrime(int n)
{
	int i, next = (n % 2) ? n + 1 : n + 2; //ensure next is odd 

	while (next < MAX)
	{
		for (i = (int)sqrt(next); i > 2; i--)
			if (next % i == 0)
				break;

		if (i == 2)
			return next;
		else
			next += 2;
	}
	return next;
}

四、参考

浙江大学 陈越、何钦铭老师主讲的数据结构

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值