
Data Structure
Networking
RDBMS
Operating System
Java
MS Excel
iOS
HTML
CSS
Android
Python
C Programming
C++
C#
MongoDB
MySQL
Javascript
PHP
- Selected Reading
- UPSC IAS Exams Notes
- Developer's Best Practices
- Questions and Answers
- Effective Resume Writing
- HR Interview Questions
- Computer Glossary
- Who is Who
Implement a Skip List in Go
Skip lists are a dynamic data structure which offer efficient insertion, search, and deletion operations. In this article, we will demonstrate the function and explore the algorithmic concepts to implement a Skip List in Go programming language. We are going to write two different examples for this demonstration. In the first example we are going to use a randomization approach and in the second example we will build the Skip List directly from randomised tower structures for quicker traversal.
Explanation
A Skip List as a data structure, maintains a sorted list of elements, to enable fast searching without the complexity of balanced trees. This is achieved through the creation of multiple lvls of linked lists with varying skip distances, helping in quicker traversal to desired elements.
Syntax
func newNode(vlue, lvl int) *node
The syntax represents a method called `newNode()` defined to accept a value and an integer to specify the tower height and return a node with its value set and an array of pointers to subsequent nodes at different levels, for the Skip List implementation.
func (sl *skipList) randomLvl() int
The syntax represents a method called `randomLvl()`defined to generate a random height for a new node in the Skip List using a probability parameter and a maximum level to determine the tower's height.
Algorithm
Start by initializing the Skip List with a base and a maximum level.
Create nodes for elements with random levels to finally form a tower-like structures.
Connect nodes horizontally within and vertically across levels.
Start searching from the upper-left corner and then move either right or down.
For insertion, update node links, while considering the tower height.
Example 1
In this example, we are going to implement a Skip List in go, using randomization. The structure node holds the values and linking pointers. The function insert adds elements by traversing levels, and the function search is defined to find an element using a multi-level search approach. The randomLvl() method generates tower heights. We have utilized arrays for the next pointers in each node for the creation of tower structure that directly stores the level of each node's tower and its connections with the next array. Finally in the main function, a Skip List is initialized with values. Lastly, element searches are performed.
package main import ( "fmt" "math/rand" ) const ( maxLvl = 16 p = 0.5 ) type node struct { vlue int nxt []*node } type skipList struct{ head *node } func newNode(vlue, lvl int) *node { return &node{vlue: vlue, nxt: make([]*node, lvl)} } func (sl *skipList) insert(vlue int) { lvl := sl.randomLvl() newNode := newNode(vlue, lvl) crrent := sl.head for i := lvl - 1; i >= 0; i-- { for crrent.nxt[i] != nil && crrent.nxt[i].vlue < vlue { crrent = crrent.nxt[i] } newNode.nxt[i], crrent.nxt[i] = crrent.nxt[i], newNode } } func (sl *skipList) search(vlue int) bool { crrent := sl.head for i := len(crrent.nxt) - 1; i >= 0; i-- { for crrent.nxt[i] != nil && crrent.nxt[i].vlue < vlue { crrent = crrent.nxt[i] } } return crrent.nxt[0] != nil && crrent.nxt[0].vlue == vlue } func (sl *skipList) randomLvl() int { lvl := 1 for rand.Float64() < p && lvl < maxLvl { lvl++ } return lvl } func main() { sl := &skipList{head: newNode(0, maxLvl)} vlues := []int{3, 6, 9, 2, 5, 8, 1, 4, 7} for _, v := range vlues { sl.insert(v) } fmt.Print("Skip List: ") crrent := sl.head.nxt[0] for crrent != nil { fmt.Printf("%d -> ", crrent.vlue); crrent = crrent.nxt[0] } fmt.Println("nil") fmt.Println("Search 5:", sl.search(5)) fmt.Println("Search 10:", sl.search(10)) }
Output
Skip List: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> nil Search 5: true Search 10: false
Example 2
In this example, we will implement a Skip List in go directly from randomized tower structures for quicker traversal. Elements are inserted through the creation of tower-like connections, and searches are performed similarly through multi-level comparisons. Randomized levels are generated in order to maintain balanced distribution. A separate linked list represents each level, and the connections are managed by the help of linked list nodes. In the main function, a Skip List is initiated and finally the element search is performed on it.
package main import ( "fmt" "math/rand" ) const ( maxLvl = 16 p = 0.5 ) type node struct { vlue int nxt []*node } type skipList struct{ head *node } func newNode(vlue, lvl int) *node { return &node{vlue: vlue, nxt: make([]*node, lvl)} } func (sl *skipList) insert(vlue int) { lvl, crrent := sl.randomLvl(), sl.head for i := lvl - 1; i >= 0; i-- { for crrent.nxt[i] != nil && crrent.nxt[i].vlue < vlue { crrent = crrent.nxt[i] } newNode := newNode(vlue, i+1) newNode.nxt[i], crrent.nxt[i] = crrent.nxt[i], newNode } } func (sl *skipList) search(vlue int) bool { crrent := sl.head for i := len(crrent.nxt) - 1; i >= 0; i-- { for crrent.nxt[i] != nil && crrent.nxt[i].vlue < vlue { crrent = crrent.nxt[i] } } return crrent.nxt[0] != nil && crrent.nxt[0].vlue == vlue } func (sl *skipList) randomLvl() int { lvl := 1 for rand.Float64() < p && lvl < maxLvl { lvl++ } return lvl } func main() { sl := &skipList{head: newNode(0, maxLvl)} vlues := []int{3, 6, 9, 2, 5, 8, 1, 4, 7} for _, v := range vlues { sl.insert(v) } fmt.Println("Skip List:") for crrent := sl.head.nxt[0]; crrent != nil; crrent = crrent.nxt[0] { fmt.Printf("%d -> ", crrent.vlue) } fmt.Println("nil") fmt.Println("Search 5:", sl.search(5)) fmt.Println("Search 10:", sl.search(10)) }
Output
Skip List: 1 -> 2 -> 3 -> 5 -> 7 -> 8 -> 9 -> nil Search 5: false Search 10: false
Real Life Implementation
Game Development: Skip lists are an excellent way of retaining the sorted organization of player scores in a gaming scenario when leaderboards or top scores are available. This makes updating and obtaining the top scores easier.
Geospatial Indexing: Skip lists have been discovered as a potential way for building geographical indexes to assist efficient storing and retrieval of geographic data. The usage of these indexes allows for the efficient retrieval of nearby places or regions, which is important for location-centric applications such as mapping services.
Conclusion
A Skip List is a versatile data structure which blends simplicity and efficiency, making it quite appropriate for maintaining ordered data with quick search, insertion, and deletion operations. In this article, we explored the concepts to implement a Skip List in go through 2 different approaches: the first approach is more memory-efficient compared to the linked list implementation because it avoids the overhead of individual pointers for each node. The next approach provides better flexibility and dynamic resizing compared to the array approach, but on the greyer side, it consumes slightly more memory due to the overhead of individual linked list nodes.