算法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);
 
        // 如果找到了对应的关键字
        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;
    }
}


结论


因此需要一种算法能够实现查找和插入操作的复杂度都很低。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值