1. Symbol tables
Symbol tables:插入键值对;给定一个key,可以搜索对应的value
-
Conventions:
- value不会是null
-
get()
返回null,如果key不存在 -
put()
重写旧的value,如果同一个key有一个新的value
-
Binary search
public Value get(Key key){ if(isEmpty()){ return null; } int i = rank(key); if(i < n && keys[i].compareTo(key) == 0){ return vals[i]; }else{ return null; } } private int rank(Key key){ int lo = 0, hi = n-1; while(lo <= hi){ int mid = (lo + hi) / 2; int cmp = key.compareTo(keys[mid]); if(cmp < 0){ hi = mid -1; }else if(cmp > 0){ lo = mid + 1; }else{ // cmp == 0 return mid; } } return lo; }
2. Binary search trees
-
定义(BST):对称排序的二叉树
- 每个节点Node都有一个键值Key, 每个Key都比它左边的subtree大,比它右边的subtree小
- Node:有一个key,一个value,两个引用指向left和right的subtree
- Search: 如果比节点小,向左比;如果比节点大,向右比;一样大,search hit
- Deletion:
- 删除最小的:向左找,直到找到一个node,它的left-link是null(说明这个node是本tree最小),然后用这个node的right-link代替它,最后update数目
- 普通删除:
- 0 child:这个node的parent-link直接用null代替
- 1 child:这个node的parent-link与它的child相连
- 2 children:找的这个node的右边subtree的最小值,将这个最小值作为继承者,然后删除这个最小值
-
BST performance:
-
N个独立不同的的Key以随机的顺序插入BST, 期望的compares( for a search/insert):~ 2 ln N.
implemen guarantee average ordered ops? operations on keys sequential search (unordered list) Search: N
insert: N
delete: NSearch: N/2
insert: N
delete: N/2No equals() binary search (ordered array) Search: lgN
insert: N
delete: NSearch: lgN
insert: N/2
delete: N/2Yes compareTo() BST Search: N
insert: N
delete: NSearch: 1.39lgN
insert: 1.39lgN
delete:Yes compareTo()
-
-
BST implementation
public class BST<Key extends Comparable<Key>, Value>{ private Node root; // root of BST private class Node{ private Key key; private Value val; private Node left; private Node right; private int count; public Node(Key key, Value val){ this.key = key; this.val = val; } } // 寻找key,如有,重置value;若没有,添加新的node // 根据相应的Key返回相应的value,若没有这个key,返回null public void put(Key key, Value val){ root = put(root, key, val); } private Node put(Node x, Key key, Value val){ if(x == null){ return new Node(key, val); } int cmp = key.compareTo(x.key); if(cmp < 0){ x.left = put(x.left, key, val); }else if(cmp > 0){ x.right = put(x.right, key, val); }else{ // cmp == 0 x.val = val; } x.count = 1 + size(x.left) + size(x.right); return x; } // 根据相应的Key返回相应的value,若没有这个key,返回null // cost: #compares = 1 + depth of node public Value get(Key key){ Node x = root; while(x != null){ int cmp = key.compareTo(x.key); if(cmp < 0){ x = x.left; }else if(cmp > 0){ x = x.right; }else{ // cmp == 0 return x.val; } } return null; } // 返回小于给定key的最大的key public Key floor(Key key){ Node x = floor(root, key); if(x == null){ return null; } return x.key; } private Node floor(Node x, Key key){ if(x == null){ return null; } int cmp = key.compareTo(x.key); if(cmp == 0){ // floor 就是这个key自己 return x; } if(cmp < 0){ // 给定的key比root的key小,说明这个key的floor一定在root的left subtree return floor(x.left, key); } // cmp > 0, 可能这个root就是我的floor,也可能在这个root的right subtree有我的floor Node t = floor(x.right, key); if(t != null){ return t; }else{ return x; } } // 一共有几key public int size(){ return size(root); } private int size(Node x){ if(x == null){ return 0; } return x.count; } // 一共有几个小于给定key的keys public int rank(Key key){ return rank(key, root); } private int rank(Key key, Node x){ if (x == null){ return 0 } int cmp = key.compareTo(x.key); if(cmp < 0){ return rank(key, x.left); }else if(cmp > 0){ return 1 + size(x.left) + rank(key, x.right); }else{ // cmp == 0 return size(x.left); } } public void deletMin(){ root = deleteMin(root); } private Node deleteMin(Node x){ if(x.left == null){ return x.right; } x.left = deleteMin(x.left); x.count = 1 + size(x.left) + size(x.right); return x; } public void delete(Key key){ root = delete(root, key); } private Node delete(Node x, Key key){ if(x == null){ return null; } int cmp = key.compareTo(x.key); // search for key if(cmp < 0){ x.left = delete(x.left, key); }else if(cmp > 0){ x.right = delete(x.right, key); }else{ if(x.right == null){ return x.left; // no right child } if(x.left == null){ return x.right; // no left child } // replace with successor Node t = x; x = min(t.right); x.right = deleteMin(t.right); x.left = t.left; } x.count = size(x.left) + size(x.right) + 1; return x; } // inorder traversal public Iterable<Key> keys(){ Queue<key> q = new Queue<Key>(); inorder(root, q); return q; } private void inorder(Node x, Queue<Key> q){ if(x == null){ return; } inorder(x.left, q); q.enqueue(x.key); inorder(x.right, q); } }