散列表分析(Java实现)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq951127336/article/details/71155757

散列表分析(Java实现)


一、 散列表的原理

散列表是一种空间换时间的存储结构,是在算法中提升效率的一种比较常用的方式。

散列表(哈希表),是指可以通过关键字key直接访问到内容value的一种数据结构。可以一个value对应多个key,但是一个key只能对应一个value,其中是通过key映射到一个位置上,来直接访问value。

这里写图片描述

而映射位置的机制,会导致可能不同key指向相同位置,这种现象成为“碰撞”。这对哈希表来说是非常不希望发生的现象。而对key进行处理转换可以避免“碰撞”现象的发生。

我们通过哈希函数使内容均匀的分配在数据结构中。

二、常见的哈希函数:

1. 直接寻址法

取关键字或关键字的某个线性函数值为散列地址。

2.数字分析法

通过对数据的分析,发现数据中冲突较少的部分,用于构造散列地址。

3.平方取中法

先求出key的平方值,然后按需要取平方值的中间几位作为散列地址。

4.取随机数法

使用rand()等随机函数构造。

5.除留取余法

取关键字被某个不大于散列表的表长n的数m除后所得的余数p为三列表地址。

三、解决“碰撞”的方法

1.开放地址法

key哈希后,发现该地值已被占用,可对该地址不断加1,直到遇到一个空的地址。

2.再哈希法

发生“碰撞”后,可对key的一部份再进行哈希处理。
详细分析http://blog.csdn.net/weiyastory/article/details/52069305

3.链地址法

链地址法是通过将key映射在同一地址上的value,做成一个链表。这是较常用方法,本文将详细讲解这种方法。

这里写图片描述

四、Java以链地址法实现散列表及分析

注意事项

  • 扩容因子
    散列表的地址使用率越大,发生“碰撞”的可能性就越大,一般在散列表地址使用率达到一定值的时候,就对散列表进行扩容,这个值称为扩容因子,为小数。

  • 关键字key
    关键字可以不为整形,但一般高级语言会把所有类型的key都转换为整形,而Java中有hashCode()方法,可以得到任何类型量的哈希值。



import java.util.Objects;

/**
 * Created by max on 17-5-3.
 */
public class MyHashTable {

    private static final int DEFAULT_INITAL_CAPACITY = 5;//定义的是默认长度

    private static final float LOAD_FACTOR = 0.75f;//扩容因子

    private Entry[] table = new Entry[DEFAULT_INITAL_CAPACITY];//初始化
    private int size =0;//哈系表大小
    private int use =0;//使用的地址数量

    private class Entry{
        int key;//关键字
        int value;
        Entry next;//链表

        public Entry(int key,int value ,Entry entry)//构造函数
        {
            super();
            this.key = key;
            this.value = value;
            this.next = entry;
        }
    }

    public void put(int key,int value){//压入内容
        int index =hash(key);//通过hash方法转换,采用的是直接法

        if (table[index]==null)//说明位置未被使用
        {
         table[index] = new Entry(-1,-1,null);
        }

        Entry tmp = table[index];
        if (tmp.next == null)//说明位置未被使用
        {
            table[index].next = new Entry(key,value,null);
            size++;
            use++;
            if (use >= table.length*LOAD_FACTOR)//判断是否需要扩容
            {
                resize();//扩容方法
            }
        }else{//已被使用,则直接扩展链表
            for (tmp = tmp.next;tmp!=null;tmp = tmp.next)
            {
                int k =tmp.key;
                if(k==key)
                {
                    tmp.value = value;
                    return;
                }
            }

            Entry temp = table[index].next;
            Entry newEntry = new Entry(key,value,temp);
            table[index].next = newEntry;
            size++;
        }

    }
    public void remove(int key) //删除,链表的中间值删除方法
    {
        int index =hash(key);
        Entry e = table[index];
        Entry pre = table[index];
        if (e!=null&& e.next!=null)
        {
            for (e=e.next;e!=null;pre =e,e =e.next)
            {
                int k =e.key;
                if(k==key)
                {
                    pre.next = e.next;
                    size--;
                    return;
                }
            }
        }
    }

    public int get(int key)//通过key提取value
    {
        int index = hash(key);
        Entry e =table[index];
        if (e!=null&&e.next!=null)
        {
            for (e=e.next;e!=null;e=e.next)
            {
                int k = e.key;
                if (k ==key)
                {
                    return e.value;
                }
            }
        }
        return -1;
    }

    public int size(){//返回元素个数
        return size;

    }

    public int getLength(){//哈系表大小
        return table.length;
    }


    private void resize() {
        int newLength = table.length*2;
        Entry[] oldTable = table;
        table = new Entry[newLength];
        use = 0;
        for(int i =0 ;i<oldTable.length;i++)
        {
            if (oldTable[i]!=null&&oldTable[i].next !=null)
            {
                Entry e = oldTable[i];
                while(null!=e.next)
                {
                    Entry next = e.next;
                    int index =hash(next.key);
                    if (table[index]==null)
                    {
                        use++;
                        table[index] = new Entry(-1,-1,null);
                    }
                    Entry temp = table[index].next;
                    Entry newEntry =new Entry(next.key,next.value,temp);
                    table[index].next = newEntry;

                    e = next;
                }
            }
        }

    }

    private int hash(int key) {//哈希方法
        return key%table.length;
    }



}

参考 《轻松学算法互联网算法面试宝典》赵烨

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试