查找:链表顺序查找和有序数组二分查找
2017-03-17 11:07
330 查看
符号表
符号表是一种存储键值对的数据结构,支持两种操作:插入(put)和查找(get)。可以分为无序符号表和有序符号表。
本节的实现基于
每个键只对应着一个值,表不允许存在重复的键
向表中存入新的键值对和已有的键冲突时,新的值会替代旧的值
键不能为空null
值不能为空null
无序链表中的顺序查找
非常的低效向一个空表插入N个不同的键需要N^2/2次比较。
只适用于小型问题,对于大型符号表很慢
public class SequentialSearchST<Key,Value>{ private Node first; // 链表首结点 private class Node{ Key key; Value val; Node next; public Node(Key key, Value val, Node next){ this.key = key; this.val = val; this.next = next; } } public Value get(Key key){ for(Node x = first; x != null; x = x.next){ if(key.equals(x.key)) return x.val; } return null; } public void put(Key key, Value val){ for(Node x = first; x != null; x = x.next){ if(key.equals(x.key)){ x.val = val; return ; } } first = new Node(key, val, first); // 放在首结点位置(链表) } }
有序数组的二分查找
rank() 是核心除了符号表的get/put等关键操作,还基于有序的数组实现其它方法
最优的查找效率和空间需求,进行有序性相关的操作。但是插入操作很慢
注:
有序数组在插入时就进行了排序。
package com.base; public class BinarySearchST<Key extends Comparable<Key>, Value> { private static final int INIT_CAPACITY = 2; private Key[] keys; private Value[] vals; private int N = 0; // 默认容量初始化 public BinarySearchST() { this(INIT_CAPACITY); } // 给定容量初始化 public BinarySearchST(int capacity) { keys = (Key[]) new Comparable[capacity]; vals = (Value[]) new Object[capacity]; } // 调整数组大小 private void resize(int capacity) { assert capacity >= N; Key[] tempk = (Key[]) new Comparable[capacity]; Value[] tempv = (Value[]) new Object[capacity]; for (int i = 0; i < N; i++) { tempk[i] = keys[i]; tempv[i] = vals[i]; } vals = tempv; keys = tempk; } // 是否包含 public boolean contains(Key key) { return get(key) != null; } // 键值对个数 public int size() { return N; } // 符号表是否为空 public boolean isEmpty() { return size() == 0; } // 根据键得到值 public Value get(Key key) { if (isEmpty()) return null; int i = rank(key); if (i < N && keys[i].compareTo(key) == 0) return vals[i]; return null; } // 返回比跟定键小的键 public int rank(Key key) { int lo = 0, hi = N-1; while (lo <= hi) { int m = lo + (hi - lo) / 2; int cmp = key.compareTo(keys[m]); if (cmp < 0) hi = m - 1; else if (cmp > 0) lo = m + 1; else return m; } return lo; } // 更新值,或插入键值 public void put(Key key, Value val) { if (val == null) { delete(key); return; } int i = rank(key); // key is already in table if (i < N && keys[i].compareTo(key) == 0) { vals[i] = val; return; } // 扩展keys if (N == keys.length) resize(2*keys.length); for (int j = N; j > i; j--) { keys[j] = keys[j-1]; vals[j] = vals[j-1]; } keys[i] = key; vals[i] = val; N++; } // 删除键值对 public void delete(Key key) { if (isEmpty()) return; // compute rank int i = rank(key); // key not in table if (i == N || keys[i].compareTo(key) != 0) { return; } for (int j = i; j < N-1; j++) { keys[j] = keys[j+1]; vals[j] = vals[j+1]; } N--; keys = null; // to avoid loitering vals = null; // resize if 1/4 full if (N > 0 && N == keys.length/4) resize(keys.length/2); } // 删除最小键和关联的值 public void deleteMin() { if (isEmpty()) throw new RuntimeException("Symbol table underflow error"); delete(min()); } // 删除最大键和关联的值 public void deleteMax() { if (isEmpty()) throw new RuntimeException("Symbol table underflow error"); delete(max()); } /***************************************************************************** * Ordered symbol table methods * 有序符号表的方法 *****************************************************************************/ // 最小 public Key min() { if (isEmpty()) return null; return keys[0]; } // 最大 public Key max() { if (isEmpty()) return null; return keys[N-1]; } // 排名在k的键 public Key select(int k) { if (k < 0 || k >= N) return null; return keys[k]; } // 小于等于key的最大键 public Key floor(Key key) { int i = rank(key); if (i < N && key.compareTo(keys[i]) == 0) return keys[i]; if (i == 0) return null; else return keys[i-1]; } // 大于等于key的最小键 public Key ceiling(Key key) { int i = rank(key); if (i == N) return null; else return keys[i]; } // lo--hi 之间的键的数量 public int size(Key lo, Key hi) { if (lo.compareTo(hi) > 0) return 0; if (contains(hi)) return rank(hi) - rank(lo) + 1; else return rank(hi) - rank(lo); } // 迭代 public Iterable<Key> keys() { return keys(min(), max()); } public Iterable<Key> keys(Key lo, Key hi) { Queue<Key> queue = new Queue<Key>(); if (lo == null && hi == null) return queue; if (lo == null) throw new RuntimeException("lo is null in keys()"); if (hi == null) throw new RuntimeException("hi is null in keys()"); if (lo.compareTo(hi) > 0) return queue; for (int i = rank(lo); i < rank(hi); i++) queue.enqueue(keys[i]); if (contains(hi)) queue.enqueue(keys[rank(hi)]); return queue; } }
相关文章推荐
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现) (转载)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现,附代码)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现) .
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)
- 查找算法集:顺序查找、二分查找、插值查找、动态查找(数组实现、链表实现)