链地址法实现HashMap

前注:本文介绍的HashMap并非Java类库的实现。而是根据哈希表知识的一个实现。

上文介绍了开放地址法实现HashTable,它的缺点是对hashCode映射为地址后如果出现重复地址,则会占用其他元素的位置。这样HashTable存储容量有限,而且不便于算法理解。本文介绍链地址法实现HashMap。

链地址法内部仍然有一个数组,但区别与开放地址法,该数组存储的是一个链表的引用。当根据hashCode计算出数组下表后,对元素的增删查改都是在该数组元素所指向的链表上完成的。这就解决了hashCode重复的问题。因为,当hashCode重复,多个元素对应同一个地址,但元素实际存储的位置在数组对应的链表上。所以相同hashCode的不同元素可以存储在同一位置。

下面是代码实现:

package org.lyk.impl;

import java.util.ArrayList;
import org.lyk.interfaces.IMap;

public class HashMap<K,V> implements IMap<K, V>
{
    private class KeyValue
    {
        private K key;
        private V value;

        public KeyValue(K key, V value)
        {
            this.key = key;
            this.value = value;
        }

        public K getKey()
        {
            return key;
        }
        public void setKey(K key)
        {
            this.key = key;
        }
        public V getValue()
        {
            return value;
        }
        public void setValue(V value)
        {
            this.value = value;
        }

    }
    private int maxSize = 10;
//    private int currentAmmount = 0;
    private Object[] table;

    public HashMap()
    {
        this.table = new Object[this.maxSize];
        for(int i = 0; i < this.maxSize; i++)
        {
            this.table[i] = new java.util.ArrayList<KeyValue>();
        }
    }

    @Override
    public void add(K key, V value)
    {
        int index = this.getIndex(key);
        ((java.util.List<KeyValue>)this.table[index]).add(new KeyValue(key, value));
    }

    @Override
    public boolean remove(K key)
    {
        int index = this.getIndex(key);
        java.util.List<KeyValue> kvs = (java.util.List<KeyValue>)this.table[index];
        int listIndex = -1;
        for(KeyValue kv : kvs)
        {
            if(kv.key.equals(key))
            {
                listIndex = kvs.indexOf(kv);
            }
        }
        if(listIndex != -1)
        {
            kvs.remove(listIndex);
            return true;
        }
        return false;
    }

    @Override
    public V get(K key)
    {
        KeyValue kv= this.find(key);
        if(kv != null)
            return kv.getValue();
        else
            return null;
    }

    @Override
    public boolean contains(K key)
    {
        if(this.get(key) != null)
            return true;
        else
            return false;
    }

    @Override
    public void replace(K key, V value)
    {
        KeyValue kv = this.find(key);
        if(kv != null)
        {
            kv.setValue(value);

        }
    }

    private int getIndex(K key)
    {
        return Math.abs(key.hashCode())%this.maxSize;
    }

    private KeyValue find(K key)
    {
        int index = this.getIndex(key);
        java.util.List<KeyValue> kvs = (java.util.List<KeyValue>)this.table[index];
        int listIndex = -1;
        for(KeyValue kv : kvs)
        {
            if(kv.key.equals(key))
            {
                return kv;
            }
        }

        return null;
    }
}

HashMap

package org.lyk.impl;

import java.math.BigInteger;

public class Info
{
    private String name;
    private String address;
    private Integer age; 

    public Info(String name, String address, Integer age)
    {
        super();
        this.name = name;
        this.address = address;
        this.age = age;
    }
    @Override
    public int hashCode()
    {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((address == null) ? 0 : address.hashCode());
        result = prime * result + ((age == null) ? 0 : age.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

//    @Override
//    public int hashCode()
//    {
//        final int prime = 27;
//        int result = 1;
//        result = prime*result + (this.name == null ? 0:this.name.hashCode());
//        result = prime*result + (this.address == null ? 0:this.address.hashCode());
//        result = prime*result + (this.age == null ? 0 : this.age.hashCode());
//        return result;
//    }

    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Info other = (Info) obj;
        if (address == null)
        {
            if (other.address != null)
                return false;
        } else if (!address.equals(other.address))
            return false;
        if (age == null)
        {
            if (other.age != null)
                return false;
        } else if (!age.equals(other.age))
            return false;
        if (name == null)
        {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
    public String getAddress()
    {
        return address;
    }
    public void setAddress(String address)
    {
        this.address = address;
    }
    public Integer getAge()
    {
        return age;
    }
    public void setAge(Integer age)
    {
        this.age = age;
    }
    @Override
    public String toString()
    {
        return "Info [name=" + name + ", address=" + address + ", age=" + age
                + "]";
    }

}

Info

package org.lyk.main;

import java.util.ArrayList;
import java.util.List;

import org.lyk.impl.HashMap;
import org.lyk.impl.Info;

public class Main
{
    public static void main(String[] args)
    {
        HashMap<String, Info> hm = new HashMap<String, Info>();
        for(int i = 0; i < 15; i++)
        {
            hm.add("sheldon" + i, new Info("sheldon" + i, "address" + i, i));
        } 

        String key = "sheldon12";
        Info sheldon12 = new Info("sheldon12", "洛杉矶", 99);
        System.out.println(hm.get(key));
        hm.replace(key, sheldon12);
        System.out.println(hm.get(key));
        hm.remove(key);
        System.out.println(hm.get(key));
        System.out.println("///~ main done");
    } 

}

Main测试

时间: 2024-10-11 09:44:11

链地址法实现HashMap的相关文章

哈希(hash) 之插入和查找(链地址法)

一:学些心得 1 getHash函数的设计最牛的是Unix中处理字符串的ELFHash():当然也可以自己写一个比较简单的getHash函数关键在于去mod M的M值,使器均匀的分布(一般是不大于hash_size的某一个素数,接近于2的某次幂):但是有一点需要注意就是返回的hash值必须是正值. 2 处理冲突的方法:链地址法是比较好的方法了(静态动态都可以的):二次哈希(一般是加key值)再探测:或者加1再探测 3 插入和查找以及删除的第一步都是一样的,getHash(),时候存在-- 4 对

哈希表——线性探测法、链地址法、查找成功、查找不成功的平均长度

一.哈希表 1.概念 哈希表(Hash Table)也叫散列表,是根据关键码值(Key Value)而直接进行访问的数据结构.它通过把关键码值映射到哈希表中的一个位置来访问记录,以加快查找的速度.这个映射函数就做散列函数,存放记录的数组叫做散列表. 2.散列存储的基本思路 以数据中每个元素的关键字K为自变量,通过散列函数H(k)计算出函数值,以该函数值作为一块连续存储空间的的单元地址,将该元素存储到函数值对应的单元中. 3.哈希表查找的时间复杂度 哈希表存储的是键值对,其查找的时间复杂度与元素数

【算法与数据结构】哈希表-链地址法

哈希表的链地址法来解决冲突问题 将所有关键字为同义词的记录存储在同一个线性链表中,假设某哈希函数产生的哈希地址在区间[0, m - 1]上,则设立一个至振兴向量 Chain  ChainHash[m]; 数据结构 //链表结点 typedef struct _tagNode { int data; //元素值(关键字) struct _tagNode* next; //下一个结点 }Node, *PNode; //哈希表结点 typedef struct _tagHashTable { //这里

哈希表(链地址法处理冲突)(1012)

Description 采用除留余数法(H(key)=key %n)建立长度为n的哈希表,处理冲突用链地址法.建立链表的时候采用尾插法. Input 第一行为哈西表的长度:第二行为关键字的个数n: 第三行为关键字集合: 第四行为要查找的数据. Output 如果查找成功,输出该关键字所在哈希表中的地址和比较次数:如果查找不成功,输出-1. Sample Input 1 2 3 4 5 13 13 16 74 60 43 54 90 46 31 29 88 77 78 79 16   Sample

C++链地址法实现哈希表

哈希表,也叫散列表,是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做哈希函数,存放记录的数组叫做哈希表. 哈希函数最主要的设计在于哈希函数和冲突处理的解决,其中哈希函数的设计方法主要有直接定址法和除留余数法:冲突处理的方法主要有开放定址法和链地址法.本文主要实现了一个基本存放字符串的哈希表,冲突处理采用链地址法. 代码如下: #include <iostream> #include<c

C# Dictionary源码剖析---哈希处理冲突的方法有:开放定址法、再哈希法、链地址法、建立一个公共溢出区等

参考:https://blog.csdn.net/exiaojiu/article/details/51252515 http://www.cnblogs.com/wangjun1234/p/3719635.html 源代码版本为 .NET Framework 4.6.1 Dictionary是Hashtable的一种泛型实现(也是一种哈希表)实现了IDictionary泛型接口和非泛型接口等,将键映射到相应的值.任何非 null 对象都可以用作键.使用与Hashtable不同的冲突解决方法,D

Java解决Hash(散列)冲突的四种方法--开放地址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区

最近时间有点紧,暂时先放参考链接了,待有时间在总结一下: 查了好多,这几篇博客写的真心好,互有优缺点,大家一个一个看就会明白了: 参考 1. 先看这个明白拉链法(链地址法),这个带源码,很好看懂,只不过是只讲了拉链法一种: 2. 再看这个比较全的,四种全讲了,链接,这篇比较形象,有图.但是这两篇都没有仔细介绍优缺点: 3. 最后看优缺点,点击这里: 原文地址:https://www.cnblogs.com/gjmhome/p/11372883.html

哈希查找解决地址冲突的两种最常见方法(线性探测再散列,链地址法)C++实现

#include<iostream>#include<iomanip>using namespace std; typedef struct Node{ int data; struct Node *next;}node; int len,num,M,numbers,i=0,mod,count=0;int *a;node **p,*s;float ASL=0,ASL1=0; int ListLength(node * head){ int length=0; node *p; p=

poj3349(哈希+链地址法)

给出N个六边形的6个边长,问其中是否有完全相同的两个六边形,完全相同包括边的长度和位置都要相同.边给出的顺序是逆时针或者顺时针的. 给每个6边形一个哈希值,方法是对6条边长度的平方和取模 #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 1e6; const int mod = 999983;//100W以内的大素数 typedef l