Hash 如何将输入映射到具有相同输出和均匀分布保证的输出?

Hash 如何将输入映射到具有相同输出和均匀分布保证的输出?,hash,rust,mapping,distribution,uniform-distribution,Hash,Rust,Mapping,Distribution,Uniform Distribution,我有一组大小可变的输入(在我的例子中是字符串),需要映射到一组大小固定的输出(在我的例子中是数组的索引)。因此,我基本上需要一个函数,如: fn map(input: String) -> usize; 我需要保证两件事: 对于任何输入X我必须始终返回相同的输出Y。例如:每次我将字符串“hello”传递给我的函数时,返回的值必须始终相同,例如1 返回值的分布必须一致,即对于无限多的输入,相同返回值的平均值必须相同。例如,如果我有M=4不同的返回值,并且我有N=100不同的输入,则映射到每

我有一组大小可变的输入(在我的例子中是字符串),需要映射到一组大小固定的输出(在我的例子中是数组的索引)。因此,我基本上需要一个函数,如:

fn map(input: String) -> usize;
我需要保证两件事:

  • 对于任何输入
    X
    我必须始终返回相同的输出
    Y
    。例如:每次我将字符串
    “hello”
    传递给我的函数时,返回的值必须始终相同,例如
    1
  • 返回值的分布必须一致,即对于无限多的输入,相同返回值的平均值必须相同。例如,如果我有
    M=4
    不同的返回值,并且我有
    N=100
    不同的输入,则映射到每个输出的输入数必须理想地等于
    25
  • 我想出了以下代码:

    use std::collections::hash_map::DefaultHasher;
    use std::hash::{Hash, Hasher};
    
    fn main() {
        let bucket = Bucket::new(5);
        let inputs = ["hello", "world", "house", "hi"];
    
        for input in &inputs {
            let output = bucket.get(input);
            assert_eq!(output, bucket.get(input));
            println!("{} -> {}", input, output);
        }
    }
    
    pub struct Bucket {
        values: Vec<usize>,
    }
    
    impl Bucket {
        pub fn new(size: usize) -> Self {
            let values = (0..size).collect();
            Bucket { values }
        }
    
        pub fn get<T: Hash>(&self, id: &T) -> usize {
            let mut hasher = DefaultHasher::new();
            Hash::hash(id, &mut hasher);
            let index = (hasher.finish() % self.values.len() as u64) as usize;
            self.values[index]
        }
    }
    
    使用std::collections::hash\u map::DefaultHasher;
    使用std::hash::{hash,Hasher};
    fn main(){
    让bucket=bucket::new(5);
    让输入=[“你好”、“世界”、“房子”、“你好”];
    用于输入(&I){
    让输出=bucket.get(输入);
    assert_eq!(输出,bucket.get(输入));
    println!(“{}->{}”,输入,输出);
    }
    }
    pub结构桶{
    价值观:Vec,
    }
    impl铲斗{
    pub fn new(尺寸:usize)->Self{
    让值=(0..size).collect();
    Bucket{values}
    }
    pub fn get(&self,id:&T)->usize{
    让mut hasher=DefaultHasher::new();
    散列::散列(id,&mut散列器);
    让index=(hasher.finish()%self.values.len()作为u64)作为usize;
    自我价值[索引]
    }
    }
    

    我认为上面的代码保证了第一点(对于相同的输入总是相同的输出),但不一定保证第二点(分布的均匀性)


    这样一个函数是否有一个快速的实现,以保证这两个点?

    我想你是正确的,第一点与你的实现是一致的

    关于第二点:这取决于
    DefaultHasher
    的功能。在实践中,这可能已经足够好了,但还有另一种技术可以满足您的需求:

    • 有一个计数器
      m
      ,最初为0
    • HashMap
      映射到
      usize
    • 每当您想
      获取结果时,请在
      HashMap
      中查找给定的字符串:
      • 如果字符串已存在,则返回关联的值
      • 如果该字符串尚未出现:
      • 将新条目添加到将给定字符串映射到当前值
        m
        HashMap
      • m
        增加1
      • 如果
        m==m
        ,则将m重置为0

    这需要O(N)内存如果我没有弄错的话,这种方法的问题是我需要将
    Bucket::get
    操作变成一个可变操作,使用
    &mut self
    来增加这个计数器,在多线程上下文中,这个计数器需要一个带互斥锁的写锁,这将大大降低impl的速度。输入/输出是作为一个整体给出的吗?如果是这样的话,您可以将所有这些作为预处理来完成(在预处理中,易变性不应该是太大的问题)。只有在启动时作为一个整体提供输出(固定),而输入不是,每个新请求都可以提供一个新的输入。