📜  跳过列表|套装2(插入)

📅  最后修改于: 2021-04-17 08:28:55             🧑  作者: Mango

我们已经讨论了“跳过列表”的概念以及它们如何在“跳过列表”中工作。设置1(简介)。在本文中,我们将讨论如何在“跳过列表”中插入元素。

决定节点级别

列表中的每个元素都由一个节点表示,在插入列表时会随机选择节点的级别。级别不取决于节点中元素的数量。节点的级别由以下算法决定-

randomLevel()
lvl := 1
//random() that returns a random value in [0...1)
while random() < p and lvl < MaxLevel do
lvl := lvl + 1
return lvl

MaxLevel是跳过列表中级别数的上限。可以确定为– L(N) = log_{p/2}{N} 。上面的算法确保随机级别永远不会大于MaxLevel。在此, p是具有级别i指针也具有级别i + 1指针的节点的分数,而N是列表中节点的数量。

节点结构

每个节点都包含一个键和一个前向数组,其中包含指向不同级别节点的指针。级别i节点携带索引为0到i的i个前向指针。
跳过节点

插入跳过列表

我们将从列表中的最高级别开始,将当前节点的下一个节点的密钥与要插入的密钥进行比较。基本思想是-

  1. 下一个节点的密钥小于要插入的密钥,然后我们继续在同一级别上前进
  2. 下一个节点的密钥大于要插入的密钥,然后我们将指向当前节点i的指针存储在update [i]处,并向下移动一级并继续我们的搜索。

在级别0处,我们肯定会找到一个插入给定键的位置。以下是插入算法的伪代码–

Insert(list, searchKey)
local update[0...MaxLevel+1]
x := list -> header
for i := list -> level downto 0 do
    while x -> forward[i] -> key  forward[i]
update[i] := x
x := x -> forward[0]
lvl := randomLevel()
if lvl > list -> level then
for i := list -> level + 1 to lvl do
    update[i] := list -> header
    list -> level := lvl
x := makeNode(lvl, searchKey, value)
for i := 0 to level do
    x -> forward[i] := update[i] -> forward[i]
    update[i] -> forward[i] := x

在这里,update [i]保持指向第i层节点的指针,从该指针我们向下移动到第i-1层,而将节点的指针保留到第0层的插入位置。考虑这个示例,我们要在其中插入键17 –
插入节点
以下是在跳过列表中插入密钥的代码–

C++
// C++ code for inserting element in skip list
  
#include 
using namespace std;
  
// Class to implement node
class Node
{
public:
    int key;
  
    // Array to hold pointers to node of different level 
    Node **forward;
    Node(int, int);
};
  
Node::Node(int key, int level)
{
    this->key = key;
  
    // Allocate memory to forward 
    forward = new Node*[level+1];
  
    // Fill forward array with 0(NULL)
    memset(forward, 0, sizeof(Node*)*(level+1));
};
  
// Class for Skip list
class SkipList
{
    // Maximum level for this skip list
    int MAXLVL;
  
    // P is the fraction of the nodes with level 
    // i pointers also having level i+1 pointers
    float P;
  
    // current level of skip list
    int level;
  
    // pointer to header node
    Node *header;
public:
    SkipList(int, float);
    int randomLevel();
    Node* createNode(int, int);
    void insertElement(int);
    void displayList();
};
  
SkipList::SkipList(int MAXLVL, float P)
{
    this->MAXLVL = MAXLVL;
    this->P = P;
    level = 0;
  
    // create header node and initialize key to -1
    header = new Node(-1, MAXLVL);
};
  
// create random level for node
int SkipList::randomLevel()
{
    float r = (float)rand()/RAND_MAX;
    int lvl = 0;
    while (r < P && lvl < MAXLVL)
    {
        lvl++;
        r = (float)rand()/RAND_MAX;
    }
    return lvl;
};
  
// create new node
Node* SkipList::createNode(int key, int level)
{
    Node *n = new Node(key, level);
    return n;
};
  
// Insert given key in skip list
void SkipList::insertElement(int key)
{
    Node *current = header;
  
    // create update array and initialize it
    Node *update[MAXLVL+1];
    memset(update, 0, sizeof(Node*)*(MAXLVL+1));
  
    /*    start from highest level of skip list
        move the current pointer forward while key 
        is greater than key of node next to current
        Otherwise inserted current in update and 
        move one level down and continue search
    */
    for (int i = level; i >= 0; i--)
    {
        while (current->forward[i] != NULL &&
              current->forward[i]->key < key)
            current = current->forward[i];
        update[i] = current;
    }
  
    /* reached level 0 and forward pointer to 
       right, which is desired position to 
       insert key. 
    */
    current = current->forward[0];
  
    /* if current is NULL that means we have reached
       to end of the level or current's key is not equal
       to key to insert that means we have to insert
       node between update[0] and current node */
    if (current == NULL || current->key != key)
    {
        // Generate a random level for node
        int rlevel = randomLevel();
  
        // If random level is greater than list's current
        // level (node with highest level inserted in 
        // list so far), initialize update value with pointer
        // to header for further use
        if (rlevel > level)
        {
            for (int i=level+1;iforward[i] = update[i]->forward[i];
            update[i]->forward[i] = n;
        }
        cout << "Successfully Inserted key " << key << "\n";
    }
};
  
// Display skip list level wise
void SkipList::displayList()
{
    cout<<"\n*****Skip List*****"<<"\n";
    for (int i=0;i<=level;i++)
    {
        Node *node = header->forward[i];
        cout << "Level " << i << ": ";
        while (node != NULL)
        {
            cout << node->key<<" ";
            node = node->forward[i];
        }
        cout << "\n";
    }
};
  
// Driver to test above code
int main()
{
    // Seed random number generator
    srand((unsigned)time(0));
  
    // create SkipList object with MAXLVL and P 
    SkipList lst(3, 0.5);
  
    lst.insertElement(3);
    lst.insertElement(6);
    lst.insertElement(7);
    lst.insertElement(9);
    lst.insertElement(12);
    lst.insertElement(19);
    lst.insertElement(17);
    lst.insertElement(26);
    lst.insertElement(21);
    lst.insertElement(25);
    lst.displayList();
}


Python
# Python3 code for inserting element in skip list
  
import random
  
class Node(object):
    '''
    Class to implement node
    '''
    def __init__(self, key, level):
        self.key = key
  
        # list to hold references to node of different level 
        self.forward = [None]*(level+1)
  
class SkipList(object):
    '''
    Class for Skip list
    '''
    def __init__(self, max_lvl, P):
        # Maximum level for this skip list
        self.MAXLVL = max_lvl
  
        # P is the fraction of the nodes with level 
        # i references also having level i+1 references
        self.P = P
  
        # create header node and initialize key to -1
        self.header = self.createNode(self.MAXLVL, -1)
  
        # current level of skip list
        self.level = 0
      
    # create  new node
    def createNode(self, lvl, key):
        n = Node(key, lvl)
        return n
      
    # create random level for node
    def randomLevel(self):
        lvl = 0
        while random.random() self.level:
                for i in range(self.level+1, rlevel+1):
                    update[i] = self.header
                self.level = rlevel
  
            # create new node with random level generated
            n = self.createNode(rlevel, key)
  
            # insert node by rearranging references 
            for i in range(rlevel+1):
                n.forward[i] = update[i].forward[i]
                update[i].forward[i] = n
  
            print("Successfully inserted key {}".format(key))
  
    # Display skip list level wise
    def displayList(self):
        print("\n*****Skip List******")
        head = self.header
        for lvl in range(self.level+1):
            print("Level {}: ".format(lvl), end=" ")
            node = head.forward[lvl]
            while(node != None):
                print(node.key, end=" ")
                node = node.forward[lvl]
            print("")
  
# Driver to test above code
def main():
    lst = SkipList(3, 0.5)
    lst.insertElement(3)
    lst.insertElement(6)
    lst.insertElement(7)
    lst.insertElement(9)
    lst.insertElement(12)
    lst.insertElement(19)
    lst.insertElement(17)
    lst.insertElement(26)
    lst.insertElement(21)
    lst.insertElement(25)
    lst.displayList()
  
main()


输出:

Successfully Inserted key 3
Successfully Inserted key 6
Successfully Inserted key 7
Successfully Inserted key 9
Successfully Inserted key 12
Successfully Inserted key 19
Successfully Inserted key 17
Successfully Inserted key 26
Successfully Inserted key 21
Successfully Inserted key 25

*****Skip List*****
Level 0: 3 6 7 9 12 17 19 21 25 26 
Level 1: 3 6 12 17 25 
Level 2: 6 12 17 25 
Level 3: 12 17 25 

注意:节点的级别是随机决定的,因此输出可能会有所不同。
时间复杂度(平均): O(log n)
时间复杂度(最差): O(n)
在下一篇文章中,我们将讨论“跳过列表”中的搜索和删除。
参考

  • ftp://ftp.cs.umd.edu/pub/skipLists/skiplists.pdf