java 数据结构之初探哈希表

  • 哈希表的底层是数组实现的.可以方便插入和查找操作.
  • 在往数据里添加值时有俩种计算位置的方式
    • (1): 开放地址法,当发生冲突的时候。找到数组中空的位置插入进去。使用开放地址法会把别人的位置挤掉.
    • (2) : 链式存储法 当发现hashcode的值相同时,以链表的方式存入进去.
  • 具体上代码:
  • 先是开放地址法:

info 类

public class Info {

    private String key;
    private String name;
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
     Info(String key, String name) {
        super();
        this.key = key;
        this.name = name;
    }
     Info() {
        super();
        // TODO Auto-generated constructor stub
    }


}

hash 表:

public class HashTable {

    private Info[] arr;

    public HashTable() {
        arr = new Info[100];
    }

    public Info[] getArr() {
        return arr;
    }

    public void setArr(Info[] arr) {
        this.arr = arr;
    }

    /**
     * 插入数据
     * 
     * @param info
     */
    public void  insert(Info info) {
        // arr[info.getKey()] = info;//使用 int 作为 key
        String key = info.getKey();// 使用string 作为KEY

        int hashVal = hashcode(key);
        // 如果只删除name 那name 就是空
        while (arr[hashVal] != null && arr[hashVal].getName() != null) {
            // 进行递加
            ++hashVal;
            // 循环
            hashVal %= hashVal;
        }

        arr[hashVal] = info;

    }

    /**
     * 查找数据
     * 
     * @param key
     * @return
     */
    public Info find(String key) {
        int hashVal = hashcode(key);
        while(arr[hashVal] !=null){
            if(arr[hashVal].getKey().equals(key)){
                return arr[hashVal];
            }

            ++hashVal;
            hashVal %= arr.length;
        }
        return null;
    }
    /**
     * 删除
     * @param key
     * @return
     */
    public Info delete(String key){
        int hashVal = hashcode(key);
        while(arr[hashVal] !=null){
            if(arr[hashVal].getKey().equals(key)){
                Info temp = arr[hashVal];
                arr[hashVal] = null;
                return temp;
            }

            ++hashVal;
            hashVal %= arr.length;
        }
        return null;
    }

    public int hashcode(String key) {
        // 这样有重复的
        // int hashVal = 0;
        // for(int i = key.length()-1; i>=0; i--){
        // int letter =key.charAt(i)-96; //空格是96 a是97
        // hashVal += letter;
        // }

        // 2)使用幂的连乘
        // int hashVal = 0;
        // int pow27 = 1;
        // for(int i = key.length()-1; i>=0; i--){
        // int letter =key.charAt(i)-96; //空格是96 a是97
        //
        // hashVal += letter*pow27; //26 个字母还有空格
        // pow27 *= pow27;
        // }

        // 压缩:并且使用bigint
        BigInteger hashVal = new BigInteger("0");
        BigInteger pow27 = new BigInteger("1");

        for (int i = key.length() - 1; i >= 0; i--) {
            int letter = key.charAt(i) - 96; // 空格是96 a是97
            BigInteger letterB = new BigInteger(String.valueOf(letter));
            hashVal = hashVal.add(letterB.multiply(pow27));
            pow27 = pow27.multiply(new BigInteger(String.valueOf(27)));
            // hashVal += letter*pow27; //26 个字母还有空格
            // pow27 *= pow27;
            // }
            // 对数组的长度取余

        }
        return hashVal.mod(new BigInteger(String.valueOf(arr.length))).intValue();
    }

}

接下来是测试代码:


    public static void main(String[] args) {

        HashTable  h = new HashTable();

        h.insert(new Info("abc","aa"));
        h.insert(new Info("bbb","bb"));

        System.out.println(h.find("abc").getName());
        System.out.println(h.find("bbb").getName());
        h.delete("bbb");
        System.out.println(h.find("bbb"));
    }
    输出:
aa
bb
null

abc 和bbb 计算出来的hash 值是一样的.但是还可以存放.其实这里是通过占用别人的位置实现的这个功能.有很大的弊端

接下来我们看 使用链式存储法,和HashMap 的原理非常相似


这里写图片描述

本来想自己画一张图的.但是太懒了.不想画了

理论和上图一样. 开始就是一个链表式的数组. 如果计算出他们的hash 值相同就链式存储下去. 如果查找和删除 计算的hash值相同 就使用 key.equals 来查找.

很多面试者都会被问到hashMap 的原理和底层实现.相信自己动手写过哈希表的人一定会说出来 底层就是hi哈希表实现的.或者是链式的数组..如果只是回答数组的话…那这个人80%没有学习过数据结构….

好了.废话不多说上代码:

public class Info {

    private String key;
    private String name;
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
     Info(String key, String name) {
        super();
        this.key = key;
        this.name = name;
    }
     Info() {
        super();
        // TODO Auto-generated constructor stub
    }


}

节点类:


/**
 * 
 * @功能:节点
 * @版本:1.0
 * @修改:
 */
public class Node {

    public Info info;

    public Node next;

    public Node(Info info){
        this.info= info;

    }

}

链表:

public class LinkList {

    //头结点
    public Node first;

    //插入一个节点在头结点后面插入

    public void insertFirst(Info info){
        Node node = new Node(info);
        node.next= first;
        first = node;

    }

    //在头结点后面进行删除。
    public Node deleteFirst(){
        Node temp =first;
        first = temp.next;
        return temp;

    }


    public Node  find(String key){
        Node current =first;

        while(!key.equals(current.info.getKey())){

            if(current.next == null){
                return null;
            }
            current = current.next;

        }

        return current;
    }

    /**
     * 删除一个节点
     * @param key
     * @return
     */
    public Node delete(String  key){
        Node current = first;
        Node previous = first;

        while(!key.equals(current.info.getKey())){
            if(current.next ==null){
                return null;
            }

            previous = current;
            current = current.next;

        }

        if(current == first){
            //如果是第一个 那么他下一个为第一个
            first = first.next;
        }else{
            //不是第一个。
            previous.next = current.next;
        }
        return current;
    }
}

hashtable 的实现:

public class HashTable {

    private LinkList[] arr;

    public HashTable(int maxSize) {
        arr = new LinkList[maxSize];
    }
    public HashTable() {
        arr = new LinkList[100];
    }



    /**
     * 插入数据
     * 
     * @param info
     */
    public void  insert(Info info) {
        // arr[info.getKey()] = info;//使用 int 作为 key
        String key = info.getKey();// 使用string 作为KEY

        int hashVal = hashcode(key);

        if(arr[hashVal] == null){
            arr[hashVal] = new LinkList();
        }

        arr[hashVal].insertFirst(info);

    }

    /**
     * 查找数据
     * 
     * @param key
     * @return
     */
    public Info find(String key) {
        int hashVal = hashcode(key);
    return  arr[hashVal].find(key).info;
    }
    /**
     * 删除
     * @param key
     * @return
     */
    public Info delete(String key){
        int hashVal = hashcode(key);
        return  arr[hashVal].delete(key).info;

    }

    public int hashcode(String key) {
        // 这样有重复的
        // int hashVal = 0;
        // for(int i = key.length()-1; i>=0; i--){
        // int letter =key.charAt(i)-96; //空格是96 a是97
        // hashVal += letter;
        // }

        // 2)使用幂的连乘
        // int hashVal = 0;
        // int pow27 = 1;
        // for(int i = key.length()-1; i>=0; i--){
        // int letter =key.charAt(i)-96; //空格是96 a是97
        //
        // hashVal += letter*pow27; //26 个字母还有空格
        // pow27 *= pow27;
        // }

        // 压缩:并且使用bigint
        BigInteger hashVal = new BigInteger("0");
        BigInteger pow27 = new BigInteger("1");

        for (int i = key.length() - 1; i >= 0; i--) {
            int letter = key.charAt(i) - 96; // 空格是96 a是97
            BigInteger letterB = new BigInteger(String.valueOf(letter));
            hashVal = hashVal.add(letterB.multiply(pow27));
            pow27 = pow27.multiply(new BigInteger(String.valueOf(27)));
            // hashVal += letter*pow27; //26 个字母还有空格
            // pow27 *= pow27;
            // }
            // 对数组的长度取余

        }
        return hashVal.mod(new BigInteger(String.valueOf(arr.length))).intValue();
    }

}

测试类:

public static void main(String[] args) {

    HashTable  h = new HashTable();

    h.insert(new Info("a","aa"));
    h.insert(new Info("ct","bb"));
    h.insert(new Info("b","zqp"));


    System.out.println(h.find("a").getName());
    System.out.println(h.find("ct").getName());
    System.out.println(h.find("b").getName());
    System.out.println(h.hashcode("a"));
    System.out.println(h.hashcode("ct"));
    System.out.println(h.delete("a"));
}

aa
bb
zqp
1
1
com.ch17.Info@83dae1

可以看到 a 和 ct 的hash 值是一样的.但是ct并没有占到别人的位置,而是链式存储到了 下标为 1 的那个链表上去了.

以前对hashMap 的原理只是知道他是怎么实现的.今天学习完哈希表数据结构之后.对他的理解更深.

猜你喜欢

转载自blog.csdn.net/qq_29371103/article/details/72820860