1.学习“哈希表查找(散列表)”
先明白“哈希表查找”的定义:
“散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系 f ,使得每个关键字key(键值)对应一个存储位置。这种对应关系 f 称为散列函数,又称为哈希函数,采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表”
(摘自《大话数据结构》)
哈希表查找重点在于:先分类再查找,通过计算缩小范围,加快查找速度。相对于普通的数组查找与链表查找,哈希表查找的时间复杂度要低不少。
hash通过hash函数,将key值映射为地址,address = f [key];
常见的hash函数有六种:直接定址法、数字分析法、平方取中法、折叠法、随机数法、除留余数法。
而在c++语言中的STL库(标准模板库)中有一个关联容器“map”,map提供六种散列构造函数,在内部自动建立起key(关键字)与 数据的联系,可以提供一对一的hash,在遇到hash类问题时用map容器会方便很多
详细可参考博客:C++中的STL中map用法详解 - Boblim - 博客园 (cnblogs.com)
这里简单说一下map的调用格式吧:
#include<map>
map< 数据类型1 ,数据类型2 >数组名
(例如:map<string , int > a)
相当于 => 数组名【数据类型1】=数据类型2
(例如:string s; a[s]=1; )
2.听学长讲课
3.完成题目
题目要求输入两行字符串,第一行字符串为主串。需要在主串中查找能与第二行字符串完全匹配的子串出现的位置,并输出每个位置上的最长相等前缀长。
一道标准的模板题,先定义分析子串前后缀相似度的函数“get_next()”,找出每个位置上的前后缀相似度的值并赋给其next[]数组,而后再在“index_kmp()”函数中进行字符串匹配。
按题目输出要求,在查找每个位置的最大前后缀相似度时用一个数组存储相似度,字符串匹配时,若匹配成功则可直接输出匹配首位置。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char s[1000100],t[1000100];
int ls,lt,next1[1000100],nextval[1000100];
/*通过计算返回子串t的next数组*/
void get_next()
{
int i=0,k=-1;
next1[0]=-1;
while(i < lt)/*此处t【0】表示串t的长度*/
{
if(k == -1 || t[i] == t[k])
{
++i;++k;
nextval[i]=k;
if(t[i] != t[k])/*若当前字符与前缀字符不同*/
next1[i]=k;/*则当前的k为next[i]的值*/
else next1[i]=next1[k];/*若与前缀字符相同,则将前缀字符的next[]值赋给i位置上的next[]*/
}
else k=next1[k];/*若字符不同则k值回溯*/
}
}
/*返回子串t在主串s中第pos个字符之后的位置,若不存在则返回值为0*/
/*t非空,1<=pos<=strlength(s)*/
void index_kmp()
{
int i=0,j=0;
get_next();/*对串t分析,得到next数组*/
while(i < ls && j < lt)/*当i小于s长度同时j小于t的长度时,循环继续*/
{
if(j == -1 || s[i] == t[j])/*两串字符匹配则继续*/
{++i;++j;}
else j=next1[j];/*指针后退重新匹配,j退回合适的位置,i不变*/
if(j == lt)
{
cout<<i-lt+1<<endl;
j=next1[j];/*j值回溯到合适的位置*/
}
}
}
int main()
{
cin>>s>>t;
ls=strlen(s);lt=strlen(t);
index_kmp();
for(int i=1 ; i <= lt; i++ )
cout<<nextval[i]<<" ";
system("pause");
return 0;
}
(2).于是他错误的点名开始了 - 洛谷
很明显的一道hash类题目,为了避免暴力循环后的时间超限,我们将每个同学的名字视作键值,利用关联容器“map”将名字(字符串类型)与整型建立联系,这样就可以做到:将字符串作为数组下标计算。
将没有报到名字的同学标记为1,叫到了的标记为2,按要求输出即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
string k;
int n,m;
map<string,int>map_name;
int main()
{
cin>>n;
int i,j;
for(i=1;i<=n;i++)
{
cin>>k;
map_name[k]=1;/*将同学的名字标记为1*/
}
cin>>m;
for(i=1;i<=m;i++)
{
cin>>k;
if(map_name[k] == 2)
cout<<"REPEAT"<<endl;
else
{
if(map_name[k] == 1)
{
map_name[k]++;
cout<<"OK"<<endl;
}
else cout<<"WRONG"<<endl;
}
}
system("pause");
return 0;
}