<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SkipList 跳表的原理以及實現(xiàn)

          共 13801字,需瀏覽 28分鐘

           ·

          2021-08-29 17:56

          一、概念

          何為跳表呢?
          我們先維基百科對其定義繼續(xù)剖析:
          跳躍列表是一種數(shù)據(jù)結(jié)構(gòu)。它允許快速查詢一個有序連續(xù)元素的數(shù)據(jù)鏈表,而其快速查詢是通過維護一個多層次的鏈表,且每一層鏈表中的元素是前一層鏈表元素的子集。
          一開始時,算法在最稀疏的層次進行搜索,直至需要查找的元素在該層兩個相鄰的元素中間。這時,算法將跳轉(zhuǎn)到下一個層次,重復(fù)剛才的搜索,直到找到需要查找的元素為止。跳過的元素的方法可以是隨機性選擇或確定性選擇,其中前者更為常見。


          什么意思呢?
          我們知道二分法查詢是依賴數(shù)組的隨機訪問,也只能應(yīng)用于數(shù)組結(jié)構(gòu),而鏈表基于`二分法查詢`類似的查詢也就成了我們所講的跳表結(jié)構(gòu)。
          其原理就是對有序的鏈表增加上附加的前進鏈接,增加是以隨機化的方式進行的,所以在列表中的查找可以快速的跳過部分列表,因此得名。所有操作都以對數(shù)隨機化的時間進行。


          跳表最底層是一個全量的有序鏈表,上層可以說是下層的“快速跑道”


          二、性質(zhì)

          (1)由很多層結(jié)構(gòu)組成;
          (2)每一層都是一個有序的鏈表;
          (3)最底層(Level 1)的鏈表包含所有元素;
          (4)如果一個元素出現(xiàn)在 Level i 的鏈表中,則它在 Level i 之下的鏈表也都會出現(xiàn);
          (5)每個節(jié)點包含兩個指針,一個指向同一鏈表中的下一個元素,一個指向下面一層的元素。


          三、實現(xiàn)

          (一)初始化

          // 構(gòu)建一個跳表節(jié)點屬性
          private static class SkipListNode<T>{
                  T val;&emsp;
                  SkipListNode<T> next,down;&emsp;
                  double sorce;

                  SkipListNode(){}
                  SkipListNode(T val,double sorce){
                      this.val = val;
                      this.sorce =sorce;
                  }
              }
              // 層數(shù)
              private int level = 0;
              // 頂層節(jié)點
              private SkipListNode<T> top; 
              public SkipList(int level){
                  this.level=level;
                  int i = level;
                  SkipListNode<T> temp = null;
                  SkipListNode<T> pre = null;
                  while (i--!==0){
                      temp = new SkipListNode<T>(null,Double.MIN_VALUE);
                      temp.down = pre;
                      pre = temp;
                  }
                  top = temp;
              }

          (二)查找

          public T get(double socre){
                  SkipListNode<T> t = top;
                  while (t!=null){
                      if(t.sorce==socre){
                          return t.val;
                      }
                      if(t.next==null){
                          if(t.down!=null){
                              t = t.down;
                              continue;
                          }else {
                              return null;
                          }
                      }
                      if(t.next.sorce>socre){
                          t = t.down;
                      }else {
                          t = t.next;
                      }
                  }
                  return null;
              }

          三)插入

           public void put(double socre,T val){
                  //1,找到需要插入的位置
                  SkipListNode<T> t = top, cur = null;//若cur不為空,表示當(dāng)前score值的節(jié)點存在
                  List<SkipListNode<T>> path = new ArrayList<>();//記錄每一層當(dāng)前節(jié)點的前驅(qū)節(jié)點
                  while (t != null) {
                      if (t.score == score) {
                          cur = t;
                          break;//表示存在該值的點,表示需要更新該節(jié)點
                      }
                      if (t.next == null) {
                          path.add(t);//需要向下查找,先記錄該節(jié)點
                          if (t.down != null) {
                              t = t.down;
                              continue;
                          } else {
                              break;
                          }
                      }
                      if (t.next.score > score) {
                          path.add(t);//需要向下查找,先記錄該節(jié)點
                          if (t.down == null) {
                              break;
                          }
                          t = t.down;
                      } else
                          t = t.next;
                  }
                  if (cur != null) {
                      while (cur != null) {
                          cur.val = val;
                          cur = cur.down;
                      }
                  } else {//當(dāng)前表中不存在score值的節(jié)點,需要從下到上插入
                      int lev = getRandomLevel();
                      if (lev > level) {//需要更新top這一列的節(jié)點數(shù)量,同時需要在path中增加這些新的首節(jié)點
                          SkipListNode<T> temp = null;
                          SkipListNode<T> prev = top;//前驅(qū)節(jié)點現(xiàn)在是top了
                          while (level++ != lev) {
                              temp = new SkipNode<T>(null, Double.MIN_VALUE);
                              path.add(0, temp);//加到path的首部
                              temp.down = prev;
                              prev = temp;
                          }
                          top = temp;//頭節(jié)點
                          level = lev;//level長度增加到新的長度
                      }
                      //從后向前遍歷path中的每一個節(jié)點,在其后面增加一個新的節(jié)點
                      SkipListNode<T> downTemp = null, temp = null, prev = null;
          //            System.out.println("當(dāng)前深度為"+level+",當(dāng)前path長度為"+path.size());
                      for (int i = level - 1; i >= level - lev; i--) {
                          temp = new SkipNode<T>(val, score);
                          prev = path.get(i);
                          temp.next = prev.next;
                          prev.next = temp;
                          temp.down = downTemp;
                          downTemp = temp;
                      }
                  }
              }
              private int getRandomLevel(){
                  int lev = 1;
                  while (random.nextInt() % 2 == 0)
                      lev++;
                  return  lev;
              }

          (四)刪除

          public void delete(double sorce){
                  SkipListNode<T> t = top;
                  while (t != null) {
                      if (t.next == null) {
                          t = t.down;
                          continue;
                      }
                      if (t.next.score == score) {
                          // 在這里說明找到了該刪除的節(jié)點
                          t.next = t.next.next;
                          t = t.down;
                          //刪除當(dāng)前節(jié)點后,還需要繼續(xù)查找之后需要刪除的節(jié)點
                          continue;
                      }
                      if (t.next.score > score)
                          t = t.down;
                      else
                          t = t.next;
                  }
              }
          來源:https://juejin.cn/post/6844903869873389582
          瀏覽 52
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  79AV成人无码 | 天天干天天骑AV | 欧美成人手机在线 | 亚洲无码天堂 | 亚洲 欧美 中文字幕 |