PTA QQ帐户的申请与登陆 思路分析及代码解析v1.0
一、前导
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;
}