数据结构 哈希查找

简介: 数据结构 哈希查找

1. DS哈希查找–链地址法


题目描述


给出一个数据序列,建立哈希表,采用求余法作为哈希函数,模数为11,哈希冲突用链地址法和表头插入


如果首次查找失败,就把数据插入到相应的位置中


实现哈希查找功能


输入


第一行输入n,表示有n个数据

第二行输入n个数据,都是自然数且互不相同,数据之间用空格隔开

第三行输入t,表示要查找t个数据

从第四行起,每行输入一个要查找的数据,都是正整数


输出


每行输出对应数据的查找结果


输入样例


6

11 23 39 48 75 62

6

39

52

52

63

63

52


输出样例


6 1

error

8 1

error

8 1

8 2


提示


注意,当两次输入要相同的查找数据,如果第一次查找不成功就会执行插入,那么第二次查找必然成功,且查找次数为1次(因为做表头插入)


例如示例数据中输入两次52,第一次查找失败就把52插入到位置8,第二次查找就成功了,所以第一次输出error,第二次就输出8 1


为什么第三次输入52会输出8 2


参考代码

#include<iostream>
using namespace std;
struct Node
{
  int data;
  int key;
  struct Node* next;
};
class HashCheck
{
  Node *Data;
  int n;
public:
  HashCheck(int n)
  {
    this->n = n;
    Data = new Node[20];
  }
  void create(int data[]);
  void Check(int e);
  void insert(int a,int e);
};
void HashCheck::insert(int a,int e)
{
  Node* p = new Node();
  p->next = Data[a].next;
  p->data = Data[a].data;
  Data[a].data = e;
  Data[a].next = p;
}
void HashCheck::create(int data[])
{
  for (int i = 0;i < n;i++)
  {
    Data[i].key = data[i]%11;
    Data[i].data = data[i];
    Data[i].next = NULL;
  }
}
void HashCheck::Check(int e)
{
  int mod = e % 11;
  int count = 0;
  int i;
  int flag=0;
  Node* p = new Node();
  for (i = 0;i < n;i++)
  {
    if (Data[i].key == mod)
    {
      flag = 1;
      p = &Data[i];
      while (p!= NULL)
      {
        count++;
        if (p->data == e)
        {
          cout << mod << " " << count << endl;
          break;
        }
        p = p->next;
      }
      if (p == NULL)
      {
        cout << "error\n";
        insert(i,e);
      }
      break;
    }
  }
  if (flag==0)
  {
    cout << "error\n";
    n = n + 1;
    Data[n-1].data = e;
    Data[n-1].key = e % 11;
    Data[n-1].next = NULL;
  }
}
int main()
{
  int n;
  int* data;
  cin >> n;
  data = new int[n];
  for (int i = 0;i < n;i++)
    cin >> data[i];
  HashCheck hc(n);
  hc.create(data);
  int t;
  cin >> t;
  int e;
  while (t--)
  {
    cin >> e;
    hc.Check(e);
  }
  return 0;
}


2. DS哈希查找—线性探测再散列


题目描述


定义哈希函数为H(key) = key%11,输入表长(大于、等于11)。输入关键字集合,用线性探测再散列构建哈希表,并查找给定关键字。


–程序要求–

若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio

程序中若include多过一个头文件,不看代码,作0分处理

不允许使用第三方对象或函数实现本题的要求


输入


测试次数t


每组测试数据为:


哈希表长m、关键字个数n


n个关键字


查找次数k


k个待查关键字


输出


对每组测试数据,输出以下信息:


构造的哈希表信息,数组中没有关键字的位置输出NULL


对k个待查关键字,分别输出:0或1(0—不成功,1—成功)、比较次数、查找成功的位置(从1开始)


输入样例


1

12 10

22 19 21 8 9 30 33 4 15 14

4

22

56

30

17


输出样例


22 30 33 14 4 15 NULL NULL 19 8 21 9

1 1 1

0 6

1 6 2

0 1


参考代码

#include<iostream>
using namespace std;
int main(){
    int t;
    cin>>t;
    while(t--){
        int m; 
        int n;
        cin>>m>>n;
        int array[m];
        for(int i= 0; i< m ; i++) 
           array[i]= -100000;
        for(int i= 0; i< n; i++){
            int shu;
            cin>>shu;
            if(array[shu%11]== -100000){
                array[shu%11]= shu;
            }
            else{
                int d= 0;
                while(true){
                    if(array[(shu%11+ d)%(m)]== -100000){
                        array[(shu%11+ d)%(m)]= shu;
                        break;
                    } 
                    else
                      d++;
                }
            }
        }
        for(int i= 0; i< m; i++){
            if(array[i]!= -100000)
              cout<<array[i];
            else
               cout<<"NULL";
            if(i!= m- 1)
              cout<<' ';
        }
        cout<<endl;
        int k;
        cin>>k;
        while(k--){
            int shu;
            cin>>shu;
            int times= 0;
            int pos= 0;
            int d= 0;
            while(true){
                times++;
                if(array[(shu%11+ d)%m]== shu){
                    cout<<"1"<<' '<<times<<' '<<(shu%11+ d)%m+ 1<<endl;
                    break;
                }
                else if(d== m||array[(shu%11+ d)%m]== -100000){
                    cout<<"0"<<' '<<times<<endl;
                    break;
                }
                else
                    d++;
            }
        }
    }
    return 0;
}


3. DS哈希查找—二次探测再散列


题目描述


定义哈希函数为H(key) = key%11。输入表长(大于、等于11),输入关键字集合,用二次探测再散列构建哈希表,并查找给定关键字。


输入


测试次数t


每组测试数据格式如下:


哈希表长m、关键字个数n


n个关键字


查找次数k


k个待查关键字


输出


对每组测试数据,输出以下信息:


构造的哈希表信息,数组中没有关键字的位置输出NULL


对k个待查关键字,分别输出:


0或1(0—不成功,1—成功)、比较次数、查找成功的位置(从1开始)


输入样例


1

12 10

22 19 21 8 9 30 33 4 41 13

4

22

15

30

41


输出样例


22 9 13 NULL 4 41 NULL 30 19 8 21 33

1 1 1

0 3

1 3 8

1 6 6


参考代码

#include <iostream>
using namespace std;
int main()
{
    int t;
    cin >> t;
    while (t--) {
        int m, n;
        cin >> m >> n;
        int* array= new int[m+ 5];
        for (int i = 0; i < m + 5; i++)
            array[i] = -100000;
        for (int i = 0; i < n; i++) {
            int shu;
            cin >> shu;
            int d = 0;
            int flag = 0;
            while (d <= m / 2) {
                flag++;
                int sym;
                if (flag >= 2&&flag% 2== 0)
                    d++;
                if (flag % 2 == 0)
                    sym = 1;
                else
                    sym = -1;
                int pos = (shu % 11 + sym * d*d) % m;
                if (pos < 0)
                    pos = m + pos;
                if (array[pos] == -100000) {
                    array[pos] = shu;
                    break;
                }
            }
        }
        for (int i = 0; i < m; i++) {
            if (array[i] == -100000)
                cout << "NULL";
            else
                cout << array[i];
            if (i != m - 1)
                cout << " ";
            else
                cout << endl;
        }
        int k;
        cin >> k;
        while (k--) {
            int shu;
            cin >> shu;
            int pos = 0;
            int times = 0;
            int d = 0;
            int flag = 0;
            while (true) {
                times++;
                flag++;
                int sym;
                if (flag >= 2 && flag % 2 == 0)
                    d++;
                if (flag % 2 == 0)
                    sym = 1;
                else
                    sym = -1;
                int pos = (shu % 11 + sym * d*d) % m;
                if (pos < 0)
                    pos = m + pos;
                if (array[pos] == -100000|| d> m/ 2) {
                    cout << "0" << ' ' << times << endl;
                    break;
                }
                if (array[pos] == shu) {
                    cout << "1" << ' ' << times <<" "<<pos + 1 << endl;
                    break;
                }
            }
        }
    }   
    return 0;
}


4. DS哈希查找–Trie树


题目描述


Trie树又称单词查找树,是一种树形结构,如下图所示。



它是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。


输入的一组单词,创建Trie树。输入字符串,计算以该字符串为公共前缀的单词数。


(提示:树结点有26个指针,指向单词的下一字母结点。)


输入


测试数据有多组


每组测试数据格式为:


第一行:一行单词,单词全小写字母,且单词不会重复,单词的长度不超过10


第二行:测试公共前缀字符串数量t


后跟t行,每行一个字符串


输出


每组测试数据输出格式为:


第一行:创建的Trie树的层次遍历结果


第2~t+1行:对每行字符串,输出树中以该字符串为公共前缀的单词数。


输入样例


abcd abd bcd efg hig

3

ab

bc

abcde


输出样例


abehbcficddggd

2

1

0


参考代码

#include <iostream>
#include <stdio.h>
#include <vector>
#include <queue>
using namespace std;
struct Node{
  char date;
  struct Node *next[26];    //next指针有26个,代表26个字母
};
class Tire{
private:
    struct Node *m;
public:
    Tire(){};
    ~Tire(){};
    void test();
    int get_num(struct Node *t);
    void level_print(struct Node *t);
};
void Tire::level_print(struct Node *t)    //层序遍历输出结果,t默认取树根
{
    queue<struct Node*> q1;            //设置一个队列,先将根结点不空的孩子加进来
    for(int i = 0; i < 26; i++)
    {
        if(t[i].date != '0')
        {
            q1.push(&t[i]);
        }
    }
    while(!q1.empty())            //在队列不空的情况下,每次输出结点对应的字符,然后将结点的孩子中不空的结点加到队列中
    {
        struct Node *t = q1.front();
        q1.pop();
        cout<<t->date;
        for(int i = 0; i < 26; i++)
        {
            if(t->next[i] != NULL)
            {
                q1.push(t->next[i]);
            }
        }
    }
    cout<<endl;
}
int Tire::get_num(struct Node *t)    //获取该结点的子树的个数,需要递归实现
{
    int coun=0;
    for(int i=0;i<26;i++)
    {
        if(t->next[i] != NULL)          //如果孩子结点不空,则计算此孩子结点的子树个数,加到父结点的子树个数中去
        {
            coun += get_num(t->next[i]);
        }
    }
    if(coun == 0)        //若最后的计算结果显示所有孩子结点都是空,证明只含有父结点这棵树,长度就是1
        return 1;
    else
        return coun;
}
void Tire::test()
{
    m = new Node[26];
    for(int i=0; i<26; i++)        //初始化结构体
    {
        m[i].date='0';
        for(int j=0;j<26;j++)
            m[i].next[j]=NULL;
    }
    char str[1024];
    int num=0;
    while((str[num] = getchar()) != '\n')    //读入第一行输入的所有单词
        num++;
    for(int i=0;i<num;i++)
    {
        string t;                    //对单词进行分割,每次分割出来的单词存在t中
        while(str[i] != ' ' && i<num)
        {
            t+=str[i];
            i++;
        }
        struct Node *father = &m[t[0]-'a'];        //设置父结点指针,方便单词加到字典树中
        father->date = t[0];
        for(int j = 1; j < t.length(); j++)
        {
            if(father->next[t[j]-'a'] != NULL)    //如果单词的第i个字母已经存在字典树中,则父节点继续往下,如果不存在,则生成新的结点加入到字典树中去
            {
                father=father->next[t[j]-'a'];
                continue;
            }
            struct Node* temp = new Node;
            temp -> date = t[j];
            for(int k = 0; k < 26; k++)
                temp->next[k] = NULL;
            father->next[t[j]-'a'] = temp;
            father = father->next[t[j]-'a'];
        }
    }
    level_print(m);        //层序遍历字典树输出结果
    int n;                //输入要检测的前缀的个数
    cin>>n;
    string temp;
    for(int i=0;i<n;i++)
    {
        cin>>temp;        //输入前缀
        struct Node *father = &m[temp[0]-'a'];
        for(int j=1;j<temp.length();j++)            //father指针取前缀的最后一个字母在树中的位置,如果不存在,则father指针为空
        {
            father = father->next[temp[j]-'a'];
            if(father == NULL)
                break;
        }
        if(father==NULL)            //若father指针为空,则前缀不存在字典树中,输出0
            cout<<0<<endl;
        else                        //若father指针不为空,则调用计算子树个树函数,输出father指针的子树的个数,此个数即为具有此公共前缀的单词的个数
        {
            int coun = get_num(father);
            cout<<coun<<endl;
        }
    }
}
int main()
{
    Tire t;
    t.test();
  return 0;
}


相关文章
|
7月前
|
算法
【数据结构】哈希经典应用:位图——[深度解析](8)
【数据结构】哈希经典应用:位图——[深度解析](8)
|
7月前
|
存储 算法 搜索推荐
【数据结构】哈希经典应用:布隆过滤器(哈希+位图)——[深度解析](9)
【数据结构】哈希经典应用:布隆过滤器(哈希+位图)——[深度解析](9)
|
7月前
|
NoSQL Redis
Redis的常用数据结构之哈希类型
Redis的常用数据结构之哈希类型
38 0
|
6月前
|
存储 算法 NoSQL
数据结构和算法——哈希查找冲突处理方法(开放地址法-线性探测、平方探测、双散列探测、再散列,分离链接法)
数据结构和算法——哈希查找冲突处理方法(开放地址法-线性探测、平方探测、双散列探测、再散列,分离链接法)
224 1
|
7月前
|
算法 程序员 测试技术
【数据结构-哈希表 一】【原地哈希】:缺失的第一个正整数
【数据结构-哈希表 一】【原地哈希】:缺失的第一个正整数
88 0
|
7月前
|
存储 搜索推荐 Serverless
[数据结构]-哈希
[数据结构]-哈希
|
6月前
|
存储 算法
数据结构和算法——了解哈希表(哈希查找、散列的基本思想)
数据结构和算法——了解哈希表(哈希查找、散列的基本思想)
50 0
|
7月前
|
存储 算法 安全
[数据结构与算法]哈希算法
[数据结构与算法]哈希算法
|
7月前
|
存储 算法 Java
数据结构与算法面试题:实现一个哈希表,并考虑哈希冲突的解决方案。
数据结构与算法面试题:实现一个哈希表,并考虑哈希冲突的解决方案。
64 0
|
7月前
|
算法
【数据结构】盘点那些经典的 [哈希面试题]【哈希切割】【位图应用】【布隆过滤器】(10)
【数据结构】盘点那些经典的 [哈希面试题]【哈希切割】【位图应用】【布隆过滤器】(10)