数据结构与算法之散列

散列以常数时间执行插入、删除和查找技术

散列不支持findMax,findMin等排序操作

分离链接法

如图:

在Java中对象要作为key要实现***equals***和***hascode***方法。

装填因子

λ为散列表中的元素个数对该表大小的比。

不使用链表的散列表

线性探测法

适用场景: λ <0.5,也就是元素不到表大小的一半情况下。 hash = x mode TableSize,如果原先的位置上已经有人了,那就往后挪动,一直到找到一个空位置。

平方探测法

原理 : hash = x mode TableSize,如果位置上已经有人了,那么就采用hash + 1^2 ,如果还是有人,那么接着用 hash - 1^2 , 如果还是有人,那么接下来用 hash + 2^2 = hash + 4, 如果 有人,同样, 采用 hash - 2^2 = hash - 4......等等,一直到找到位置为止。

双散列

原理 : hash(x) = R - (x mod R) 其中,R是小于TableSize的素数

代码如下:

分离链接散列表

public class SeparateChainingHashTable<AnyType> {

    private int size ;

    public SeparateChainingHashTable(){
        this(DEFAULT_TABLE_SIZE);
    }
    public SeparateChainingHashTable(int size) {
        theLists = new LinkedList[nextPrime(size)];
        for (int i = 0; i< theLists.length ; i++){
            theLists[i] = new LinkedList<AnyType>();
        }
    }

    public void insert(AnyType x) {
        List<AnyType> whichList = theLists[myhash(x)];
        if (!whichList.contains(x)){
            whichList.add(x);
            //rehash
            if (++ currentSize > theLists.length){
                rehash();
            }
        }
    }

    public void remove(AnyType x){
        List<AnyType> whichList = theLists[myhash(x)];
        if (whichList.contains(x)){
            whichList.remove(x);
            currentSize -- ;
        }
    }

    public boolean contains(AnyType x){
        List<AnyType> whichList =theLists[myhash(x)];
        return whichList.contains(x);
    }

    public void makeEmpty(){
        for (int i=0; i < theLists.length ; i++){
            theLists[i].clear();
        }
        currentSize = 0;
    }

    private static final int DEFAULT_TABLE_SIZE = 101;


    private List<AnyType>[] theLists;
    private int currentSize;

    private void rehash(){
        List<AnyType>[] oldArray = theLists;

        theLists = new List[nextPrime(2* theLists.length)];
        for (int j = 0; j < theLists.length ; j++){
            theLists[j] = new LinkedList<>();
        }

        //copy
        currentSize = 0;
        for(int i= 0; i < oldArray.length ; i++){
            for (AnyType item : oldArray[i]){
                insert(item);
            }
        }
    }

    private int myhash(AnyType x){
            int hashVal = x.hashCode();

            hashVal %= theLists.length;
            if(hashVal < 0 ){
                hashVal += theLists.length;
            }
            return hashVal;
    }

    private static int nextPrime(int n){
        if (n <= 2) {
            return 2;
        }else{
            while (!isPrime(n)) {
                n++;
            }
            return n;
        }
    }
    private static boolean isPrime(int n){
        for (int i = 2; i < sqrt(n); i++) {
            if (n%i == 0) {
                return false;
            }
        }
        return true;
    }
}
复制代码

平方探测散列表

/**
 * 平方探测方法的散列表
 * @param <AnyType>
 */
public class QuadraticProbingHashTable<AnyType> {

    public QuadraticProbingHashTable(){
        this(DEFAULT_TABLE_SIZE);
    }

    public QuadraticProbingHashTable(int size){
        allocateArray(size);
        makeEmpty();
    }

    public void makeEmpty(){
        currentSize = 0;
        for (int i=0; i<array.length ; i++){
            array[i] = null;
        }
    }

    public boolean contains(AnyType x){
        int currentPos = findPos(x);
        return isActive(currentPos);
    }

    public void insert(AnyType x){
        int pos = findPos(x);
        while(isActive(pos)){ // duplicate,do nothing
           return;
        }

        array[currentSize] = new HashEntry<AnyType>(x,true);
        //rehash
        if (++ currentSize >= array.length /2 ){
            rehash();
        }
    }

    public void remove(AnyType x){
        int currentPos = findPos(x);
        if (isActive(currentPos)){
            array[currentPos].isActive = false;
        }
    }


    private static class HashEntry<AnyType>{
        public AnyType element;
        public boolean isActive;

        public HashEntry(AnyType e){
            this(e,true);
        }

        public HashEntry(AnyType e,boolean i){
          this.element = e;
          this.isActive = i;
        }
    }

    private static final int DEFAULT_TABLE_SIZE = 11;
    private HashEntry<AnyType>[] array;
    private int currentSize;

    private void allocateArray(int arraySize){
        array = new HashEntry[arraySize];
    }

    private boolean isActive(int currentPos){
//        if (currentPos < 0 || currentPos > currentSize){
//            return false;
//        }
//        //forget to judge null
//        return array[currentPos].isActive;
        return array[currentPos] != null && array[currentPos].isActive;
    }

    private int findPos(AnyType x){
        int offset = 1;
        int currentPos = myhash(x);

        while(array[currentPos] != null && !array[currentPos].element.equals(x)){
            currentPos += offset;
            offset += 2;//todo why???
            if (currentPos >= array.length){
                currentPos -= array.length; // 从头开始
            }
        }
        return currentPos;
    }
    private void rehash(){
        HashEntry<AnyType>[] oldArray = array;
        //create a new double-sized empty table
        allocateArray(nextPrime(2* oldArray.length));
        currentSize = 0;

        //copy
        for (int i=0; i < oldArray.length ; i++){
            if(oldArray[i] != null && oldArray[i].isActive){
                insert(oldArray[i].element);
            }
        }
    }

    private int myhash(AnyType x){
        int hashVal = x.hashCode();

        hashVal %= array.length;
        if(hashVal < 0 ){
            hashVal += array.length;
        }
        return hashVal;
    }


    private static int nextPrime(int n){
        if (n <= 2) {
            return 2;
        }else{
            while (!isPrime(n)) {
                n++;
            }
            return n;
        }
    }
    private static boolean isPrime(int n){
        for (int i = 2; i < sqrt(n); i++) {
            if (n%i == 0) {
                return false;
            }
        }
        return true;
    }

}

复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值