第四周下:Symbol Tables

1. Symbol tables

  1. Symbol tables:插入键值对;给定一个key,可以搜索对应的value

  2. Conventions:

    • value不会是null
    • get() 返回null,如果key不存在
    • put() 重写旧的value,如果同一个key有一个新的value
  3. 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

  1. 定义(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的最小值,将这个最小值作为继承者,然后删除这个最小值
  2. 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: N
      Search: N/2
      insert: N
      delete: N/2
      No equals()
      binary search (ordered array) Search: lgN
      insert: N
      delete: N
      Search: lgN
      insert: N/2
      delete: N/2
      Yes compareTo()
      BST Search: N
      insert: N
      delete: N
      Search: 1.39lgN
      insert: 1.39lgN
      delete: \sqrt N
      Yes compareTo()
  1. 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);
       }
    }
    
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容