散列

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. 一篇文章搞懂G1收集器

    一.何为G1收集器 The Garbage-First (G1) garbage collector is a server-style garbage collector, targeted for ...

  2. Linux系统CentOS进入单用户模式和救援模式详解

    一.概述 目前在运维日常工作中,经常会遇到服务器异常断电.忘记root密码.系统引导文件损坏无法进入系统等等操作系统层面的问题,给运维带来诸多不便,现将上述现象的解决方法和大家分享一下,本次主要以Ce ...

  3. nextLine()和next()的区别和使用方法

    最近在笔试,刷剑指Offer时,都是只需要把方法实现了就行.但是!!!笔试时候会发现,大部分会要求你把main函数也code出来,真是醉了,第一次笔试时候搞的晕乎乎的..... 废话不多说,那么在写输 ...

  4. hdu-1159 1087 1257(dp)

    本文就最长公共子序列,最长连续递增子序列的长度,最大连续递增子序列的值进行对比. hdu-1159: Common Subsequence Time Limit: 2000/1000 MS (Java ...

  5. 关于优先队列的总结II

    优先队列这个数据结构还是很有用的,可以帮我们解决很多棘手的排序的问题,所以再来细细看一下, priority_queue<Type, Container, Functional> Type ...

  6. python xml转excle

    <?xml version="1.0" encoding="UTF-8"?> <RECORDS xmlns:xsi="http:// ...

  7. 010. NET5_命令参数读取+配置多种读取

    上节课遗留问题:上节脚本启动后,CSS样式丢失问题 解决办法:a.拷贝丢失的wwwroot目录:b. 给UesStaticFiles类指定读取wwwroot目录 静态文件读取 Nuget引入:Micr ...

  8. App icons generator

    App icons generator https://appicon.co/ Drag or select an app icon image (1024x1024) to generate dif ...

  9. Navigator.registerProtocolHandler All In One

    Navigator.registerProtocolHandler All In One Web API custom protocol URL Schemes URL Protocols https ...

  10. API 授权 All In One

    API 授权 All In One 身份验证 授权类型 身份验证类型 继承认证 没有认证 API密钥 不记名令牌 基本认证 摘要授权 OAuth 1.0 OAuth 2.0 授权码 隐含的 密码凭证 ...