算法设计与分析 有序表

简介: 算法设计与分析 有序表

有序表

有序表

  • 作用:支持哈希表的所有操作,key是按照有序进行组织的(哈希表是无序的)
  • 时间复杂度:所有的操作都是O(log N)级别的
  • 实现方式:
    (1)红黑树
    (2)AVL
    (3)SBT
    (4)跳表(skiplist)
    (1),(2),(3)均属性BST(平衡搜索二叉树)

搜索二叉树

  • 搜索二叉树中,一般没有重复项,可以在节点中增加数据项,记录节点数据出现的次数
  • 插入:每次插入节点均从头节点,若插入节点比头节点小往左与其子节点进行比较,若比头节点大往右进行比较,重复比较,直至到空节点,将该节点插入到空节点即可
  • 删除:
    (1)叶子节点,搜索该节点,并记录该节点的父节点,修改父节点指针便可实现删除
    (2)只有左 / 右节点,搜索该节点,记录其父节点与其子节点,修改父节点指针,使用子节点替换删除节点
    (3)左右孩子都有:搜索该节点,使用该节点左树的最右节点 / 右树的最左节点 替换删除节点,再将最右 / 最左节点的子节点与其父节点相连即可
  • 缺点:时间复杂度受数据提供顺序的影响
  • 改变树的平衡性:
    image.png
  • 左旋:头节点向左边倒
    (1)p节点向左边倒,右孩子 x,成为头节点
    (2)p成为x的左孩子
    (3)将x 的左孩子给到p,成为p的右孩子
    image.png
    public void leftRotate(Node cur) {
      Node right = cur.r;
      cur.r = right.l;
      right.l = cur;
    }
  • 右旋:头节点向左边倒
    (1)p节点向右边倒,左孩子 x,成为头节点
    (2)p成为x的右孩子
    (3)将x 的右孩子给到p,成为p的左孩子image.png
  public Node rightRotate(Node cur) {
      Node left = cur.l;
      cur.l = left.r;
      left.r = cur;
    }

AVL

  • 平衡性要求:左右子树均为AVL且左右子树的高度差的决定值小于等于1
  • 平衡性的检查:
    (1)增加节点:从增加节点的位置开始以及往上进行平衡性判断
    (2)删除节点:从删除节点的位置开始以及往上进行平衡性判断,特殊的删除左右节点都存在的节点时,从替换该节点的父节点开始检查
  • 平衡性被破会的四种情况:技巧,使三个节点的中间值作为头节点,进行调整
    (1)LL:左树的左边破坏平衡,x为中间值,使x作头节点,就是y的右旋
    image.png
    (2)RR:右树的右边破坏平衡,x为中间值,使x作头节点,就是y的左旋
    image.png(3)LR:左树的右边破坏平衡,z为中间值,使z作头节点,先x左旋,再y右旋
    image.png
    (4)RL:右树的左边破坏平衡,z为中间值,使z作头节点,先x右旋,再y左旋image.png
  public static class AVLNode<K extends Comparable<K>, V> {
    public K k;
    public V v;
    public AVLNode<K, V> l;
    public AVLNode<K, V> r;
    public int h;
    public AVLNode(K key, V value) {
      k = key;
      v = value;
      h = 1;
    }
  }
  public static class AVLTreeMap<K extends Comparable<K>, V> {
    private AVLNode<K, V> root;
    private int size;
    public AVLTreeMap() {
      root = null;
      size = 0;
    }
    private AVLNode<K, V> rightRotate(AVLNode<K, V> cur) {
      AVLNode<K, V> left = cur.l;
      cur.l = left.r;
      left.r = cur;
      cur.h = Math.max((cur.l != null ? cur.l.h : 0), (cur.r != null ? cur.r.h : 0)) + 1;
      left.h = Math.max((left.l != null ? left.l.h : 0), (left.r != null ? left.r.h : 0)) + 1;
      return left;
    }
    private AVLNode<K, V> leftRotate(AVLNode<K, V> cur) {
      AVLNode<K, V> right = cur.r;
      cur.r = right.l;
      right.l = cur;
      cur.h = Math.max((cur.l != null ? cur.l.h : 0), (cur.r != null ? cur.r.h : 0)) + 1;
      right.h = Math.max((right.l != null ? right.l.h : 0), (right.r != null ? right.r.h : 0)) + 1;
      return right;
    }
    private AVLNode<K, V> maintain(AVLNode<K, V> cur) {
      if (cur == null) {
        return null;
      }
      int leftHeight = cur.l != null ? cur.l.h : 0;
      int rightHeight = cur.r != null ? cur.r.h : 0;
      if (Math.abs(leftHeight - rightHeight) > 1) {
        if (leftHeight > rightHeight) {
          int leftLeftHeight = cur.l != null && cur.l.l != null ? cur.l.l.h : 0;
          int leftRightHeight = cur.l != null && cur.l.r != null ? cur.l.r.h : 0;
          if (leftLeftHeight >= leftRightHeight) {
            cur = rightRotate(cur);
          } else {
            cur.l = leftRotate(cur.l);
            cur = rightRotate(cur);
          }
        } else {
          int rightLeftHeight = cur.r != null && cur.r.l != null ? cur.r.l.h : 0;
          int rightRightHeight = cur.r != null && cur.r.r != null ? cur.r.r.h : 0;
          if (rightRightHeight >= rightLeftHeight) {
            cur = leftRotate(cur);
          } else {
            cur.r = rightRotate(cur.r);
            cur = leftRotate(cur);
          }
        }
      }
      return cur;
    }
    private AVLNode<K, V> findLastIndex(K key) {
      AVLNode<K, V> pre = root;
      AVLNode<K, V> cur = root;
      while (cur != null) {
        pre = cur;
        if (key.compareTo(cur.k) == 0) {
          break;
        } else if (key.compareTo(cur.k) < 0) {
          cur = cur.l;
        } else {
          cur = cur.r;
        }
      }
      return pre;
    }
    private AVLNode<K, V> findLastNoSmallIndex(K key) {
      AVLNode<K, V> ans = null;
      AVLNode<K, V> cur = root;
      while (cur != null) {
        if (key.compareTo(cur.k) == 0) {
          ans = cur;
          break;
        } else if (key.compareTo(cur.k) < 0) {
          ans = cur;
          cur = cur.l;
        } else {
          cur = cur.r;
        }
      }
      return ans;
    }
    private AVLNode<K, V> findLastNoBigIndex(K key) {
      AVLNode<K, V> ans = null;
      AVLNode<K, V> cur = root;
      while (cur != null) {
        if (key.compareTo(cur.k) == 0) {
          ans = cur;
          break;
        } else if (key.compareTo(cur.k) < 0) {
          cur = cur.l;
        } else {
          ans = cur;
          cur = cur.r;
        }
      }
      return ans;
    }
    private AVLNode<K, V> add(AVLNode<K, V> cur, K key, V value) {
      if (cur == null) {
        return new AVLNode<K, V>(key, value);
      } else {
        if (key.compareTo(cur.k) < 0) {
          cur.l = add(cur.l, key, value);
        } else {
          cur.r = add(cur.r, key, value);
        }
        cur.h = Math.max(cur.l != null ? cur.l.h : 0, cur.r != null ? cur.r.h : 0) + 1;
        return maintain(cur);
      }
    }
    // 在cur这棵树上,删掉key所代表的节点
    // 返回cur这棵树的新头部
    private AVLNode<K, V> delete(AVLNode<K, V> cur, K key) {
      if (key.compareTo(cur.k) > 0) {
        cur.r = delete(cur.r, key);
      } else if (key.compareTo(cur.k) < 0) {
        cur.l = delete(cur.l, key);
      } else {
        if (cur.l == null && cur.r == null) {
          cur = null;
        } else if (cur.l == null && cur.r != null) {
          cur = cur.r;
        } else if (cur.l != null && cur.r == null) {
          cur = cur.l;
        } else {
          AVLNode<K, V> des = cur.r;
          while (des.l != null) {
            des = des.l;
          }
          cur.r = delete(cur.r, des.k);
          des.l = cur.l;
          des.r = cur.r;
          cur = des;
        }
      }
      if (cur != null) {
        cur.h = Math.max(cur.l != null ? cur.l.h : 0, cur.r != null ? cur.r.h : 0) + 1;
      }
      return maintain(cur);
    }
    public int size() {
      return size;
    }
    public boolean containsKey(K key) {
      if (key == null) {
        return false;
      }
      AVLNode<K, V> lastNode = findLastIndex(key);
      return lastNode != null && key.compareTo(lastNode.k) == 0 ? true : false;
    }
    public void put(K key, V value) {
      if (key == null) {
        return;
      }
      AVLNode<K, V> lastNode = findLastIndex(key);
      if (lastNode != null && key.compareTo(lastNode.k) == 0) {
        lastNode.v = value;
      } else {
        size++;
        root = add(root, key, value);
      }
    }
    public void remove(K key) {
      if (key == null) {
        return;
      }
      if (containsKey(key)) {
        size--;
        root = delete(root, key);
      }
    }
    public V get(K key) {
      if (key == null) {
        return null;
      }
      AVLNode<K, V> lastNode = findLastIndex(key);
      if (lastNode != null && key.compareTo(lastNode.k) == 0) {
        return lastNode.v;
      }
      return null;
    }
    public K firstKey() {
      if (root == null) {
        return null;
      }
      AVLNode<K, V> cur = root;
      while (cur.l != null) {
        cur = cur.l;
      }
      return cur.k;
    }
    public K lastKey() {
      if (root == null) {
        return null;
      }
      AVLNode<K, V> cur = root;
      while (cur.r != null) {
        cur = cur.r;
      }
      return cur.k;
    }
    public K floorKey(K key) {
      if (key == null) {
        return null;
      }
      AVLNode<K, V> lastNoBigNode = findLastNoBigIndex(key);
      return lastNoBigNode == null ? null : lastNoBigNode.k;
    }
    public K ceilingKey(K key) {
      if (key == null) {
        return null;
      }
      AVLNode<K, V> lastNoSmallNode = findLastNoSmallIndex(key);
      return lastNoSmallNode == null ? null : lastNoSmallNode.k;
    }
  }

SBT(SizeBalancedTree)

  • 平衡性要求:每颗子树的大小,不小于其兄弟子树的大小,即每颗叔叔树的大小,不小于其任何侄子树的大小image.png
  • 平衡性的检查:
    (1)增加节点:从增加节点的位置开始以及往上进行平衡性判断
    (2)删除节点:从删除节点的位置开始以及往上进行平衡性判断,特殊的删除左右节点都存在的节点时,从替换该节点的父节点开始检查
  • 平衡性被破会的四种情况:
    (1)LL:左树的左边破坏平衡,maintain为递归函数,将子树变化过的节点再次进行m调用
    image.png
    (2)RR:右树的右边破坏平衡,左旋,再将子树变化的调用m函数
    (3)LR:左树的右边破坏平衡,先左,再右旋,再将子树变化的调用m函数
    image.png
    (4)RL:右树的左边破坏平衡,先右,再左旋,再将子树变化的调用m函数
  public static class SBTNode<K extends Comparable<K>, V> {
    public K key;
    public V value;
    public SBTNode<K, V> l;
    public SBTNode<K, V> r;
    public int size; // 不同的key的数量
    public SBTNode(K key, V value) {
      this.key = key;
      this.value = value;
      size = 1;
    }
  }
  public static class SizeBalancedTreeMap<K extends Comparable<K>, V> {
    private SBTNode<K, V> root;
    private SBTNode<K, V> rightRotate(SBTNode<K, V> cur) {
      SBTNode<K, V> leftNode = cur.l;
      cur.l = leftNode.r;
      leftNode.r = cur;
      leftNode.size = cur.size;
      cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
      return leftNode;
    }
    private SBTNode<K, V> leftRotate(SBTNode<K, V> cur) {
      SBTNode<K, V> rightNode = cur.r;
      cur.r = rightNode.l;
      rightNode.l = cur;
      rightNode.size = cur.size;
      cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
      return rightNode;
    }
    private SBTNode<K, V> maintain(SBTNode<K, V> cur) {
      if (cur == null) {
        return null;
      }
      int leftSize = cur.l != null ? cur.l.size : 0;
      int leftLeftSize = cur.l != null && cur.l.l != null ? cur.l.l.size : 0;
      int leftRightSize = cur.l != null && cur.l.r != null ? cur.l.r.size : 0;
      int rightSize = cur.r != null ? cur.r.size : 0;
      int rightLeftSize = cur.r != null && cur.r.l != null ? cur.r.l.size : 0;
      int rightRightSize = cur.r != null && cur.r.r != null ? cur.r.r.size : 0;
      if (leftLeftSize > rightSize) {
        cur = rightRotate(cur);
        cur.r = maintain(cur.r);
        cur = maintain(cur);
      } else if (leftRightSize > rightSize) {
        cur.l = leftRotate(cur.l);
        cur = rightRotate(cur);
        cur.l = maintain(cur.l);
        cur.r = maintain(cur.r);
        cur = maintain(cur);
      } else if (rightRightSize > leftSize) {
        cur = leftRotate(cur);
        cur.l = maintain(cur.l);
        cur = maintain(cur);
      } else if (rightLeftSize > leftSize) {
        cur.r = rightRotate(cur.r);
        cur = leftRotate(cur);
        cur.l = maintain(cur.l);
        cur.r = maintain(cur.r);
        cur = maintain(cur);
      }
      return cur;
    }
    private SBTNode<K, V> findLastIndex(K key) {
      SBTNode<K, V> pre = root;
      SBTNode<K, V> cur = root;
      while (cur != null) {
        pre = cur;
        if (key.compareTo(cur.key) == 0) {
          break;
        } else if (key.compareTo(cur.key) < 0) {
          cur = cur.l;
        } else {
          cur = cur.r;
        }
      }
      return pre;
    }
    private SBTNode<K, V> findLastNoSmallIndex(K key) {
      SBTNode<K, V> ans = null;
      SBTNode<K, V> cur = root;
      while (cur != null) {
        if (key.compareTo(cur.key) == 0) {
          ans = cur;
          break;
        } else if (key.compareTo(cur.key) < 0) {
          ans = cur;
          cur = cur.l;
        } else {
          cur = cur.r;
        }
      }
      return ans;
    }
    private SBTNode<K, V> findLastNoBigIndex(K key) {
      SBTNode<K, V> ans = null;
      SBTNode<K, V> cur = root;
      while (cur != null) {
        if (key.compareTo(cur.key) == 0) {
          ans = cur;
          break;
        } else if (key.compareTo(cur.key) < 0) {
          cur = cur.l;
        } else {
          ans = cur;
          cur = cur.r;
        }
      }
      return ans;
    }
    // 现在,以cur为头的树上,新增,加(key, value)这样的记录
    // 加完之后,会对cur做检查,该调整调整
    // 返回,调整完之后,整棵树的新头部
    private SBTNode<K, V> add(SBTNode<K, V> cur, K key, V value) {
      if (cur == null) {
        return new SBTNode<K, V>(key, value);
      } else {
        cur.size++;
        if (key.compareTo(cur.key) < 0) {
          cur.l = add(cur.l, key, value);
        } else {
          cur.r = add(cur.r, key, value);
        }
        return maintain(cur);
      }
    }
    // 在cur这棵树上,删掉key所代表的节点
    // 返回cur这棵树的新头部
    private SBTNode<K, V> delete(SBTNode<K, V> cur, K key) {
      cur.size--;
      if (key.compareTo(cur.key) > 0) {
        cur.r = delete(cur.r, key);
      } else if (key.compareTo(cur.key) < 0) {
        cur.l = delete(cur.l, key);
      } else { // 当前要删掉cur
        if (cur.l == null && cur.r == null) {
          // free cur memory -> C++
          cur = null;
        } else if (cur.l == null && cur.r != null) {
          // free cur memory -> C++
          cur = cur.r;
        } else if (cur.l != null && cur.r == null) {
          // free cur memory -> C++
          cur = cur.l;
        } else { // 有左有右
          SBTNode<K, V> pre = null;
          SBTNode<K, V> des = cur.r;
          des.size--;
          while (des.l != null) {
            pre = des;
            des = des.l;
            des.size--;
          }
          if (pre != null) {
            pre.l = des.r;
            des.r = cur.r;
          }
          des.l = cur.l;
          des.size = des.l.size + (des.r == null ? 0 : des.r.size) + 1;
          // free cur memory -> C++
          cur = des;
        }
      }
      // cur = maintain(cur);
      return cur;
    }
    private SBTNode<K, V> getIndex(SBTNode<K, V> cur, int kth) {
      if (kth == (cur.l != null ? cur.l.size : 0) + 1) {
        return cur;
      } else if (kth <= (cur.l != null ? cur.l.size : 0)) {
        return getIndex(cur.l, kth);
      } else {
        return getIndex(cur.r, kth - (cur.l != null ? cur.l.size : 0) - 1);
      }
    }
    public int size() {
      return root == null ? 0 : root.size;
    }
    public boolean containsKey(K key) {
      if (key == null) {
        throw new RuntimeException("invalid parameter.");
      }
      SBTNode<K, V> lastNode = findLastIndex(key);
      return lastNode != null && key.compareTo(lastNode.key) == 0 ? true : false;
    }
    // (key,value) put -> 有序表 新增、改value
    public void put(K key, V value) {
      if (key == null) {
        throw new RuntimeException("invalid parameter.");
      }
      SBTNode<K, V> lastNode = findLastIndex(key);
      if (lastNode != null && key.compareTo(lastNode.key) == 0) {
        lastNode.value = value;
      } else {
        root = add(root, key, value);
      }
    }
    public void remove(K key) {
      if (key == null) {
        throw new RuntimeException("invalid parameter.");
      }
      if (containsKey(key)) {
        root = delete(root, key);
      }
    }
    public K getIndexKey(int index) {
      if (index < 0 || index >= this.size()) {
        throw new RuntimeException("invalid parameter.");
      }
      return getIndex(root, index + 1).key;
    }
    public V getIndexValue(int index) {
      if (index < 0 || index >= this.size()) {
        throw new RuntimeException("invalid parameter.");
      }
      return getIndex(root, index + 1).value;
    }
    public V get(K key) {
      if (key == null) {
        throw new RuntimeException("invalid parameter.");
      }
      SBTNode<K, V> lastNode = findLastIndex(key);
      if (lastNode != null && key.compareTo(lastNode.key) == 0) {
        return lastNode.value;
      } else {
        return null;
      }
    }
    public K firstKey() {
      if (root == null) {
        return null;
      }
      SBTNode<K, V> cur = root;
      while (cur.l != null) {
        cur = cur.l;
      }
      return cur.key;
    }
    public K lastKey() {
      if (root == null) {
        return null;
      }
      SBTNode<K, V> cur = root;
      while (cur.r != null) {
        cur = cur.r;
      }
      return cur.key;
    }
    public K floorKey(K key) {
      if (key == null) {
        throw new RuntimeException("invalid parameter.");
      }
      SBTNode<K, V> lastNoBigNode = findLastNoBigIndex(key);
      return lastNoBigNode == null ? null : lastNoBigNode.key;
    }
    public K ceilingKey(K key) {
      if (key == null) {
        throw new RuntimeException("invalid parameter.");
      }
      SBTNode<K, V> lastNoSmallNode = findLastNoSmallIndex(key);
      return lastNoSmallNode == null ? null : lastNoSmallNode.key;
    }
  }

红黑树

  • 概述:
    (1)每个节点不是红就是黑
    (2)叶节点:不是没有左右孩子的节点,而是空节点
    (3)头和叶节点,必须为黑
    (4)任何两个红节点都不能相邻
    (5)任意节点出发,到每一个叶节点的所有路径,经过的黑节点个数相同
  • 效果:从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的image.png

AVL,SBT,红黑树对比

  • 共性
    (1)都是搜索二叉树
    (2)插入、删除、查询(一切查询)都是基于搜索二叉树的
    (3)使用调整的基本动作都只有左旋、右旋
    (4)插入、删除时,从最底层被影响到的节点开始,对往上路径的节点做平衡性检查
    (5)因为只对一条向上路径的每个节点做O(1)的检查和调整,所以可以做到O(logN)
  • 不同点
    (1)平衡性的约束不同:AVL树最严格、SBT树稍宽松、红黑树最宽松(平衡性:左右子树的规模大致相同)
    (2)因为平衡性的约束不同,所以在插入,删除平衡性变化的调整上有常数时间的差别

跳表(skiplist)

  • 概述:
    (1)开始有一个默认节点(链表,其key是最小的) head
    (2)每次出发均从head出发
    (3)添加节点,该节点随机产生一个高度,若头结点的高度比其小,头结点扩充高度(只有头结点可以扩充,要保证头结点的高度最高的)
    (4)将头结点中的指针向连接节点对应层连接
    image.png
    如图:就是一个含10个数据跳表,1产生的随机高度是4,2产生的随机高度是1……
  • 基本操作
    image.png
    (1)查找:通过head找到最高层,直接通过最高层对应的元素进行比较,若最高层不行就跳到下一层,因为整体是有序的所以可以减少节点的查找
    例:查找40,最高层开始是20,小于40,于是可以跳过2,10,15,下一次直接可以100,大于,从20开始到下一层50,大于,再下一层找到40
    (2)插入:先生成插入元素对应的层数,通过查找,确定插入位置,使用插入层改变节点的连接
    例:插入70,对应2层
    image.png
    (3)删除:先查找,直接将待删除节点前的节点忽略该节点与后面节点连接即可
  • 复杂度:
    (1)用空间来换时间
    (2)如果一个链表有 n 个结点,如果每两个结点抽取出一个结点建立索引的话,那么第一级索引的结点数大约就是 n/2,第二级索引的结点数大约为 n/4,以此类推第 m 级索引的节点数大约为 n/(2^m),我们可以看出来这是一个等比数列
    (3)所以跳表的空间复杂度为 O(n)
    (4)跳表的高度计算类似与满二叉树:整个跳表的高度就是 log(n),跳表的查询的时间复杂度为 O(logn)
  public static class SkipListNode<K extends Comparable<K>, V> {
    public K key;
    public V val;
    public ArrayList<SkipListNode<K, V>> nextNodes;
    public SkipListNode(K k, V v) {
      key = k;
      val = v;
      nextNodes = new ArrayList<SkipListNode<K, V>>();
    }
    // 遍历的时候,如果是往右遍历到的null(next == null), 遍历结束
    // 头(null), 头节点的null,认为最小
    // node  -> 头,node(null, "")  node.isKeyLess(!null)  true
    // node里面的key是否比otherKey小,true,不是false
    public boolean isKeyLess(K otherKey) {
      //  otherKey == null -> false 
      return otherKey != null && (key == null || key.compareTo(otherKey) < 0);
    }
    public boolean isKeyEqual(K otherKey) {
      return (key == null && otherKey == null)
          || (key != null && otherKey != null && key.compareTo(otherKey) == 0);
    }
  }
  public static class SkipListMap<K extends Comparable<K>, V> {
    private static final double PROBABILITY = 0.5; // < 0.5 继续做,>=0.5 停
    private SkipListNode<K, V> head;
    private int size;
    private int maxLevel;
    public SkipListMap() {
      head = new SkipListNode<K, V>(null, null);
      head.nextNodes.add(null); // 0
      size = 0;
      maxLevel = 0;
    }
    // 从最高层开始,一路找下去,
    // 最终,找到第0层的<key的最右的节点
    private SkipListNode<K, V> mostRightLessNodeInTree(K key) {
      if (key == null) {
        return null;
      }
      int level = maxLevel;
      SkipListNode<K, V> cur = head;
      while (level >= 0) { // 从上层跳下层
        //  cur  level  -> level-1
        cur = mostRightLessNodeInLevel(key, cur, level--);
      }
      return cur;
    }
    // 在level层里,如何往右移动
    // 现在来到的节点是cur,来到了cur的level层,在level层上,找到<key最后一个节点并返回
    private SkipListNode<K, V> mostRightLessNodeInLevel(K key, 
        SkipListNode<K, V> cur, 
        int level) {
      SkipListNode<K, V> next = cur.nextNodes.get(level);
      while (next != null && next.isKeyLess(key)) {
        cur = next;
        next = cur.nextNodes.get(level);
      }
      return cur;
    }
    public boolean containsKey(K key) {
      if (key == null) {
        return false;
      }
      SkipListNode<K, V> less = mostRightLessNodeInTree(key);
      SkipListNode<K, V> next = less.nextNodes.get(0);
      return next != null && next.isKeyEqual(key);
    }
    // 新增、改value
    public void put(K key, V value) {
      if (key == null) {
        return;
      }
      // 0层上,最右一个,< key 的Node -> >key
      SkipListNode<K, V> less = mostRightLessNodeInTree(key);
      SkipListNode<K, V> find = less.nextNodes.get(0);
      if (find != null && find.isKeyEqual(key)) {
        find.val = value;
      } else { // find == null   8   7   9
        size++;
        int newNodeLevel = 0;
        while (Math.random() < PROBABILITY) {
          newNodeLevel++;
        }
        // newNodeLevel
        while (newNodeLevel > maxLevel) {
          head.nextNodes.add(null);
          maxLevel++;
        }
        SkipListNode<K, V> newNode = new SkipListNode<K, V>(key, value);
        for (int i = 0; i <= newNodeLevel; i++) {
          newNode.nextNodes.add(null);
        }
        int level = maxLevel;
        SkipListNode<K, V> pre = head;
        while (level >= 0) {
          // level 层中,找到最右的 < key 的节点
          pre = mostRightLessNodeInLevel(key, pre, level);
          if (level <= newNodeLevel) {
            newNode.nextNodes.set(level, pre.nextNodes.get(level));
            pre.nextNodes.set(level, newNode);
          }
          level--;
        }
      }
    }
    public V get(K key) {
      if (key == null) {
        return null;
      }
      SkipListNode<K, V> less = mostRightLessNodeInTree(key);
      SkipListNode<K, V> next = less.nextNodes.get(0);
      return next != null && next.isKeyEqual(key) ? next.val : null;
    }
    public void remove(K key) {
      if (containsKey(key)) {
        size--;
        int level = maxLevel;
        SkipListNode<K, V> pre = head;
        while (level >= 0) {
          pre = mostRightLessNodeInLevel(key, pre, level);
          SkipListNode<K, V> next = pre.nextNodes.get(level);
          // 1)在这一层中,pre下一个就是key
          // 2)在这一层中,pre的下一个key是>要删除key
          if (next != null && next.isKeyEqual(key)) {
            // free delete node memory -> C++
            // level : pre -> next(key) -> ...
            pre.nextNodes.set(level, next.nextNodes.get(level));
          }
          // 在level层只有一个节点了,就是默认节点head
          if (level != 0 && pre == head && pre.nextNodes.get(level) == null) {
            head.nextNodes.remove(level);
            maxLevel--;
          }
          level--;
        }
      }
    }
    public K firstKey() {
      return head.nextNodes.get(0) != null ? head.nextNodes.get(0).key : null;
    }
    public K lastKey() {
      int level = maxLevel;
      SkipListNode<K, V> cur = head;
      while (level >= 0) {
        SkipListNode<K, V> next = cur.nextNodes.get(level);
        while (next != null) {
          cur = next;
          next = cur.nextNodes.get(level);
        }
        level--;
      }
      return cur.key;
    }
    public K ceilingKey(K key) {
      if (key == null) {
        return null;
      }
      SkipListNode<K, V> less = mostRightLessNodeInTree(key);
      SkipListNode<K, V> next = less.nextNodes.get(0);
      return next != null ? next.key : null;
    }
    public K floorKey(K key) {
      if (key == null) {
        return null;
      }
      SkipListNode<K, V> less = mostRightLessNodeInTree(key);
      SkipListNode<K, V> next = less.nextNodes.get(0);
      return next != null && next.isKeyEqual(key) ? next.key : less.key;
    }
    public int size() {
      return size;
    }
  }


目录
相关文章
|
6月前
|
人工智能 算法
【算法分析与设计】递归与分治策略(二)
【算法分析与设计】递归与分治策略
|
1月前
|
存储 算法 搜索推荐
【算法设计与分析】—— 分治算法
【算法设计与分析】—— 分治算法
24 0
|
6月前
|
机器学习/深度学习 算法 编译器
【算法分析与设计】递归与分治策略(一)
【算法分析与设计】递归与分治策略
|
3月前
|
算法 搜索推荐
归并算法:分治而治的高效算法大揭秘(图文详解)
归并算法:分治而治的高效算法大揭秘(图文详解)
41 0
|
3月前
|
设计模式 算法 知识图谱
算法设计与分析(贪心法)
【1月更文挑战第1天】在分析问题是否具有最优子结构性质时,通常先设出问题的最优解,给出子问题的解一定是最优的结论。证明思路是:设原问题的最优解导出子问题的解不是最优的,然后在这个假设下可以构造出比原问题的最优解更好的解,从而导致矛盾。(一个问题能够分解成各个子问题来解决,通过各个子问题的最优解能递推到原问题的最优解,此时原问题的最优解一定包含各个子问题的最优解,这是能够采用贪心法来求解问题的关键)贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择获得,即通过一系列的逐步局部最优选择使得最终的选择方案是全局最优的。
74 1
|
6月前
|
算法
算法分析与设计——递归算法(一)
算法分析与设计——递归算法(一)
|
6月前
|
算法
算法分析与设计——递归算法(二)1.汉罗塔问题
算法分析与设计——递归算法(二)1.汉罗塔问题
|
6月前
|
存储 人工智能 算法
【算法分析与设计】回溯法(上)
【算法分析与设计】回溯法(上)
|
6月前
|
算法 搜索推荐 Windows
【算法分析与设计】递归与分治策略(三)
【算法分析与设计】递归与分治策略
|
6月前
|
机器学习/深度学习 存储 算法
【算法分析与设计】贪心算法(上)
【算法分析与设计】贪心算法(上)