注意本题题干说的二次探测法是平方探测法而不是线性探测二次法,第一次写时被坑了😣
平方探测法可以视为一种开放寻址法的实现方式,在 线性探查法 中,我们会一位一位的探查,这个做法容易导致扎堆,即表中连续若干个位置都被占用时,再继续线性查找这样效率过低。
为了避免这样的扎堆现象,我们进行适当改进,当表中下标为 start = x % m_size 被占用时,按照以下顺序继续查找表中位置:start + 1 * 1,start + 2 * 2,start + 3 * 3,…, start + (m_size - 1) * (m_size - 1)。如果 i 在 [0,m_size] 范围内都无法找到位置,那么当 i≥m_size时,也一定无法找到位置,所以这时即可判定无法继续插入。
关于二次探测为什么只需要探测m_size次的问题:
在二次探测的时候,k只需从0到m_size - 1探测m_size次
因为:
(i * i) % m_size 是以m_size个数为循环出现的
如m_size取5时:
0 * 0 % 5 = 0
1 * 1 % 5 = 1
2 * 2 % 5 = 4
3 * 3 % 5 = 4
4 * 4 % 5 = 1
…
5 * 5 % 5 = 0
6 * 6 % 5 = 1
所以可能的位置最多只有m_size个,若m_size个位置该元素都放不进去,则无法插入该元素
可证明:
$$
((i + m\_size) \times (i + m\_size)) \% m\_size == (i \times i) \% m\_size ~~~~(i >= 0)
$$
from collections import defaultdict
hash = defaultdict(lambda : False)
def is_prime(x):
if x < 2:
return False
for i in range(2,int(x ** 0.5) + 1):
if x % i == 0:
return False
return True
def find(x):
start = x % m_size
for i in range(m_size):
k = (start + i * i) % m_size # 平方探测法
if not hash[k]:
hash[k] = True
return k
return '-'
m_size,n = map(int,input().split())
while not is_prime(m_size):
m_size += 1
ans = []
for x in map(int,input().split()):
t = find(x)
ans.append(t)
print(*ans)