算法4-6:关联数组的基本实现

本节主要介绍键值对表的基本实现方法。


链表法


一种方法就是用链表进行实现。这样的方法的基本思想就是用链表储存键值对。当须要寻找一个值时,扫描整个链表,假设有匹配的键,就返回相应的值。当须要插入一个值时,扫描整个链表,假设可以找到匹配的键,就覆盖相应的值,假设没有找到,就在链表的头部添加一个新的键值对。


这样的算法查找操作和插入操作的复杂度均为N,性能非常差。


代码

public class LinkedST<Key extends Comparable<Key>,Value> {
    private class Node {
        Key key;
        Value value;
        Node next;
    }
 
    private Node first;
 
    public void insert(Key key, Value value) {
        Node node = search(key);
        if(node == null) {
            node = new Node();
            node.key = key;
            node.value = value;
            node.next = first;
            first = node;
        } else {
            node.value = value;
        }
    }
 
    public boolean isEmpty() {
        return first == null;
    }
 
    public Value get(Key key) {
        Node node = search(key);
        if(node != null)
            return node.value;
        return null;
    }
 
    private Node search(Key key) {
        Node node = first;
        while(node != null) {
            if(node.key.compareTo(key) == 0) {
                return node;
            }
            node = node.next;
        }
        return null;
    }
}


数组法


还有一种方法就是用数组进行实现。搜索的时候能够用二分查找。所以这样的算法查找的复杂度时logN,可是插入的复杂度依旧是N。尽管比链表略微好一点,可是插入操作的复杂度还是太高,无法满足性能要求。


代码

public class ArrayST<Key extends Comparable<Key>, Value> {
    private Key[] keys; // 注意,这里必需要两个数组分别保存key和value。假设将key和value包括在一个对象中,会导致Generic Array Creation。
    private Value[] values;
    private int N;
 
    public ArrayST(int capacity) {
        keys = (Key[])new Comparable[capacity];
        values = (Value[])new Object[capacity];
    }
 
    private void debugPrint() {
        for(int i=0;i<N;i++) {
            System.out.println(keys[i]);
        }
    }
 
    public void insert(Key key, Value value) {
        int i = search(key);
 
        // 假设找到了相应的keyword
        if(i < N && keys[i].compareTo(key) == 0) {
            // 覆盖相应的值
            values[i] = value;
        } else {
            // 插入新的值
            for(int j=N-1;j>=i;j--) {
                keys[j+1] = keys[j];
                values[j+1] = values[j];
            }
            keys[i] = key;
            values[i] = value;
            N++;
        }
    }
 
    public Value get(Key key) {
        int i = search(key);
 
        // 假设找到了相应的键
        if(i<N && keys[i].compareTo(key) == 0) {
            return values[i];
        }
 
        // 找不到
        return null;
    }
 
    public boolean isEmpty() {
        return N==0;
    }
 
    // 二分查找
    private int search(Key key) {
        int lo = 0;
        int hi = N;
        while(lo < hi) { // 注意,这里是lo < hi,而不是lo > hi
            int mid = (hi-lo)/2 + lo;
            int compare = key.compareTo(keys[mid]);
 
            // 假设key比較小,说明要找的键在左边
            if(compare < 0) {
                hi = mid;
            } else if(compare > 0) {
                // 要找的键在右边
                lo = mid+1;
            } else {
                // 正好找到想要的键
                return mid;
            }
        }
 
        // 没有找到,注意:没有找到时要返回key应该插入的位置,而不是N
        return lo;
    }
}


结论


因此须要一种算法可以实现查找和插入操作的复杂度都非常低。


原文地址:https://www.cnblogs.com/lcchuguo/p/4003546.html