散列

1078 Hashing (25 分)

Quadratic probing (with positive increments only) is used to solve the collisions.

这句话说的是使用平方探测法来解决哈希冲突,Linear Probing(线性探测法)、Quadratic probing(平方探测法)这种专业术语在平常的学习中应当认真记忆而不是认为不重要,因为这句话一开始看不懂,想当然认不重要就略过了,那结果多半WA。

知道了解决办法之后,需要处理的一个问题就是我们如何知道插入失败?

假设$x<y$,由$h(k) + x^2 = h(k) + y^2 \quad (mod \ p)$得:

$$ x^2 = y^2 \quad(mod \ p)$$

$$ (x-y)(x+y) = 0 \quad(mod \ p)$$

由上述式子推导可发现$p$是一个循环节,如果从$0 \sim p-1$进行枚举仍然找不到位置的话即可认为插入失败

这道题要求的是$with \ positive \ increments \ only$,去掉这个限制条件后,以增量序列$1^2, -1^2, 2^2, -2^2 \dots, x^2, -x^2$且$x<=p/2$循环试探下一个存储地址即可,证明同上可得(tips:大与2/p的部分可以由p减去小于2/p的部分得到)

还需要注意的一个点:1不是素数,需要在isPrime函数中加以判断

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#define ll long long
#define inf 0x3f3f3f3f
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int maxn = 1e6+100;
int p, n, tmp;
bool vis[maxn];
bool isPrime(int x){
if(x==1) return false;
for(int i = 2; i*i <= x; i++)
if(x%i==0) return false;
return true;
}
int main(){
scanf("%d%d", &p, &n);
while(!isPrime(p)) p++;
while(n--){
scanf("%d", &tmp);
int x = tmp%p, y = x, inc = -1;
while(inc<p&&vis[y]) inc++, y = (x+inc*inc)%p;
if(inc!=p) printf("%d", y), vis[y] = 1;
else printf("-");
if(n) printf(" ");
}
}

补充资料:

线性探测是按线性方法一个一个找,只要表里有空位总能将元素填入;而二次探测有可能出现表中有空间但平方探测找不到的情况

线性探测容易聚集,二次探测聚集情况较线性探测要好。

二次探测有时候探测不到整个散列表空间,是其一大缺陷。但是经过数学家的研究,散列表长度TableSize是某个4k+3(k是正整数)形式的素数时,平方探测法就可以探查到整个散列表空间.

Reference:

https://www.icourse163.org/learn/ZJU-93001?tid=1003997005#/learn/content?type=detail&id=1007588520

https://www.nowcoder.com/discuss/67780

https://en.wikipedia.org/wiki/Quadratic_probing

https://blog.csdn.net/qq_37142034/article/details/87903983

https://blog.csdn.net/pennyliang/article/details/5446961

1145 Hashing - Average Search Time (25 分)

这道题相当于1078的扩展,关键在于如何求不在散列表中的元素的平均查找次数。边界值显然为p+1,当查找到已经查找过的单元格后就知道查找失败了;在这个过程中如果发现有空位也能说明该元素不在单元格中

#include <cstdio>
using namespace std;
const int maxn = 1e6+100;
int p, n, m, tmp, h[maxn];
bool vis[maxn];
bool isPrime(int x){
if(x==1) return false;
for(int i = 2; i*i <= x; i++)
if(x%i==0) return false;
return true;
}
int main(){
scanf("%d%d%d", &p, &n, &m);
while(!isPrime(p)) p++;
while(n--){
scanf("%d", &tmp);
int x = tmp%p, y = x, inc = 0;
while(vis[y]&&++inc<p) y = (x+inc*inc)%p;
if(inc!=p) h[y] = tmp, vis[y] = 1;
else printf("%d cannot be inserted.\n", tmp);
}
int cnt = m, sum = 0;
while(m--){
scanf("%d", &tmp);
int x = tmp%p, y = x, inc = 0;
while(h[y]!=tmp&&vis[y]&&++inc<p) y = (x+inc*inc)%p;
sum += inc+1;
}
printf("%.1f", 1.0*sum/cnt);
}

PTA甲级—常用技巧与算法的更多相关文章

  1. python算法常用技巧与内置库

    python算法常用技巧与内置库 近些年随着python的越来越火,python也渐渐成为了很多程序员的喜爱.许多程序员已经开始使用python作为第一语言来刷题. 最近我在用python刷题的时候想 ...

  2. JavaScript实现常用的排序算法

    ▓▓▓▓▓▓ 大致介绍 由于最近要考试复习,所以学习js的时间少了 -_-||,考试完还会继续的努力学习,这次用原生的JavaScript实现以前学习的常用的排序算法,有冒泡排序.快速排序.直接插入排 ...

  3. 【shell 大系】Linux Shell常用技巧

    在最近的日常工作中由于经常会和Linux服务器打交道,如Oracle性能优化.我们数据采集服务器的资源利用率监控,以及Debug服务器代码并解决其效率和稳定性等问题.因此这段时间总结的有关Linux ...

  4. oracle存储过程常用技巧

    我们在进行pl/sql编程时打交道最多的就是存储过程了.存储过程的结构是非常的简单的,我们在这里除了学习存储过程的基本结构外,还会学习编写存储过程时相关的一些实用的知识.如:游标的处理,异常的处理,集 ...

  5. Vim 常用技巧:

    Vim 常用技巧: 将回车由默认的8个空格改为4个空格: 命令:set sw=4 修改tab为4空格: 命令:set ts=4 设置每一级的缩进长度: 命令:set shiftwidth=4 设置文件 ...

  6. JS~~~ 前端开发一些常用技巧 模块化结构 &&&&& 命名空间处理 奇技淫巧!!!!!!

    前端开发一些常用技巧               模块化结构       &&&&&     命名空间处理 奇技淫巧!!!!!!2016-09-29    17 ...

  7. 常用Java排序算法

    常用Java排序算法 冒泡排序 .选择排序.快速排序 package com.javaee.corejava; public class DataSort { public DataSort() { ...

  8. Android ListView 常用技巧

    Android ListView 常用技巧 Android TextView 常用技巧 1.使用ViewHolder提高效率 ViewHolder模式充分利用了ListView的视图缓存机制,避免了每 ...

  9. JavaScript常用技巧总结(持续添加中...)

    在我学习过程中收集的一些常用技巧: typeof x !== undifined 判断x是否已定义: x === Object(x)  判断x是否为对象: Object.keys(x).length ...

随机推荐

  1. 迷宫城堡 HDU - 1269 判断有向图是否是强连通图

    为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以 ...

  2. JavaScript——二

    样式: 实验二. querySelectorAll()里面如果填id名称就直接写,如果要确定某个属性的值,就要用到[ ]来具体选择,其中写多个以空格隔开就表达第一个声明下的第二个标签内部的某个属性 这 ...

  3. JavaScript——变量及作用域

  4. Codeforces Round #667 (Div. 3) D. Decrease the Sum of Digits (贪心)

    题意:给你一个正整数\(n\),每次可以对\(n\)加一,问最少操作多少次是的\(n\)的所有位数之和不大于\(s\). 题解:\(n\)的某个位置上的数进位,意味这后面的位置都可以被更新为\(0\) ...

  5. Python 闭包及装饰器

    闭包是指延伸了作用域的函数. 自由变量(free variable) 指未在本地作用域中绑定的变量 函数装饰器用于在源码中标记函数, 以某种方式增强函数的行为. 装饰器实质,把被装饰的函数替换为新函数 ...

  6. .NetCore快速上手Consul,留给自己一点思考的空间

    互联网热潮下,"微服务"技术架构成为了一种高大上的技术,其顾名思义就是将传统的大的业务服务拆分成独立的小服务,当拆分的服务慢慢多起来的时候,我们会发现服务地址很难管理,传统的方式一 ...

  7. CentOS 6 修改/etc/security/limits.conf不生效办法

    我们使用CentOS系统,在部署新的服务经常会遇到 打开最大文件数限制 too many open files的警告,通常我们只需要修改/etc/security/limits.conf该文件,增加两 ...

  8. 1077E Thematic Contests 【二分答案】

    题目:戳这里 题意:n个数代表n个problem,每个数的值代表这个问题的topic,让我们挑出一些problems,满足挑出problems的topic是首项为a1公比为2的等比数列(每种topic ...

  9. 逆元 exgcd 费马小定理 中国剩余定理的理解和证明

    一.除法取模逆元 如果我们要通过一个前面取过模的式子递推出其他要取模的式子,而递推式里又存在除法 那么一个很尴尬的事情出现了,假如a[i-1]=100%31=7 a[i]=(a[i-1]/2)%31 ...

  10. 关于string类中find函数的讲解

    以下所讲的所有的string查找函数,都有唯一的返回类型,那就是size_type,即一个无符号整数(按打印出来的算).若查找成功,返回按查找规则找到的第一个字符或子串的位置:若查找失败,返回npos ...