Imagine having a multi-level highway system for data! A Skip List is a brilliant data structure that achieves O(log n) performance for search, insertion, and deletion operations using nothing more than clever layered linked lists.
Your task is to implement a Skip List from scratch that supports:
Search: Find if a target value exists
Add: Insert a new value (duplicates allowed)
Erase: Remove a value and return success status
The Magic: Unlike traditional linked lists that require O(n) traversal, Skip Lists use multiple levels where higher levels act as "express lanes" to jump over many elements quickly. Each element has a random height, creating a probabilistic balanced structure.
Example: For a Skip List containing [30, 40, 50, 60, 70, 90], adding 45 and 80 would create new nodes that randomly appear in multiple levels, maintaining the sorted order at each level.
The optimal Skip List implementation uses probabilistic balancing through random node heights to achieve O(log n) expected performance. Key insights: use multiple levels as express lanes, maintain sorted order at each level, and leverage randomization instead of complex tree rebalancing. This creates an elegant data structure that's simpler than balanced trees but equally efficient.
Common Approaches
✓
Proper Skip List Implementation (Optimal)
⏱️ Time: O(log n)
Space: O(n)
The true Skip List implementation uses multiple levels where each node has a random height. Higher levels act as express lanes, allowing us to skip over many elements. The key insight is using randomization to achieve balance without complex rebalancing algorithms. Each level maintains sorted order, and we traverse from top to bottom, moving right when possible and down when necessary.
Simple Linked List (Linear Search)
⏱️ Time: O(n)
Space: O(n)
The simplest approach is to implement the Skip List as a regular sorted linked list. For search, traverse from head to find the target. For insertion, find the correct position and insert. For deletion, find the node and remove it. This gives us the basic functionality but doesn't leverage the Skip List's multi-level advantage.
Proper Skip List Implementation (Optimal) — Algorithm Steps
Create nodes with random heights using coin flips
Maintain multiple levels with proper linking
For search: start at top level, move right until too far, then drop down
For insertion: find insertion point at all levels, insert with random height
For deletion: find node at all levels and remove connections
Visualization
Tap to expand
Step-by-Step Walkthrough
1
Start at Top Level
Begin search from highest level of header
2
Horizontal Movement
Move right while next value is less than target
3
Vertical Drop
Drop down one level when can't go right
4
Target Found
Continue until target found or confirmed absent
Code -
solution.c — C
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#define MAX_LEVEL 16
typedef struct SkipListNode {
int val;
struct SkipListNode** forward;
} SkipListNode;
typedef struct {
int level;
SkipListNode* header;
} Skiplist;
SkipListNode* createNode(int val, int level) {
SkipListNode* node = (SkipListNode*)malloc(sizeof(SkipListNode));
node->val = val;
node->forward = (SkipListNode**)calloc(level + 1, sizeof(SkipListNode*));
return node;
}
int randomLevel() {
int level = 0;
while ((rand() & 1) && level < MAX_LEVEL) {
level++;
}
return level;
}
Skiplist* skiplistCreate() {
Skiplist* obj = (Skiplist*)malloc(sizeof(Skiplist));
obj->level = 0;
obj->header = createNode(-1, MAX_LEVEL);
return obj;
}
bool skiplistSearch(Skiplist* obj, int target) {
SkipListNode* current = obj->header;
for (int i = obj->level; i >= 0; i--) {
while (current->forward[i] && current->forward[i]->val < target) {
current = current->forward[i];
}
}
current = current->forward[0];
return current && current->val == target;
}
void skiplistAdd(Skiplist* obj, int num) {
SkipListNode* update[MAX_LEVEL + 1];
SkipListNode* current = obj->header;
for (int i = obj->level; i >= 0; i--) {
while (current->forward[i] && current->forward[i]->val < num) {
current = current->forward[i];
}
update[i] = current;
}
int newLevel = randomLevel();
if (newLevel > obj->level) {
for (int i = obj->level + 1; i <= newLevel; i++) {
update[i] = obj->header;
}
obj->level = newLevel;
}
SkipListNode* newNode = createNode(num, newLevel);
for (int i = 0; i <= newLevel; i++) {
newNode->forward[i] = update[i]->forward[i];
update[i]->forward[i] = newNode;
}
}
bool skiplistErase(Skiplist* obj, int num) {
SkipListNode* update[MAX_LEVEL + 1];
SkipListNode* current = obj->header;
for (int i = obj->level; i >= 0; i--) {
while (current->forward[i] && current->forward[i]->val < num) {
current = current->forward[i];
}
update[i] = current;
}
current = current->forward[0];
if (current && current->val == num) {
for (int i = 0; i <= obj->level; i++) {
if (update[i]->forward[i] != current) break;
update[i]->forward[i] = current->forward[i];
}
while (obj->level > 0 && !obj->header->forward[obj->level]) {
obj->level--;
}
free(current->forward);
free(current);
return true;
}
return false;
}
void skiplistFree(Skiplist* obj) {
SkipListNode* current = obj->header;
while (current) {
SkipListNode* temp = current;
current = current->forward[0];
free(temp->forward);
free(temp);
}
free(obj);
}
/* ---- stdin parsing helpers ---- */
/* Parse array of strings from JSON array like ["Skiplist","add","add","search"] */
int parseOps(const char* line, char ops[][32], int maxOps) {
int count = 0;
const char* p = line;
while (*p && count < maxOps) {
if (*p == '"') {
p++;
int i = 0;
while (*p && *p != '"' && i < 31) ops[count][i++] = *p++;
ops[count][i] = '\0';
count++;
if (*p == '"') p++;
} else {
p++;
}
}
return count;
}
/* Parse array of arrays like [[],[1],[2],[0]] into flat int params and a count per entry */
int parseParams(const char* line, int params[][2], int* paramCounts, int maxEntries) {
int count = 0;
const char* p = line;
/* skip outer [ */
while (*p && *p != '[') p++;
if (*p == '[') p++;
while (*p && count < maxEntries) {
/* find inner [ */
while (*p && *p != '[' && *p != ']') p++;
if (*p == ']') break; /* end of outer array */
if (*p == '[') {
p++; /* skip inner [ */
paramCounts[count] = 0;
while (*p && *p != ']') {
while (*p && !isdigit((unsigned char)*p) && *p != '-' && *p != ']') p++;
if (*p == ']') break;
if (isdigit((unsigned char)*p) || *p == '-') {
char* end;
params[count][paramCounts[count]] = (int)strtol(p, &end, 10);
paramCounts[count]++;
p = end;
}
}
if (*p == ']') p++;
count++;
}
}
return count;
}
int main() {
/* Fixed seed for deterministic behavior */
srand(42);
static char opsLine[4096];
static char valsLine[4096];
if (!fgets(opsLine, sizeof(opsLine), stdin)) return 1;
if (!fgets(valsLine, sizeof(valsLine), stdin)) return 1;
static char ops[256][32];
int opCount = parseOps(opsLine, ops, 256);
static int params[256][2];
static int paramCounts[256];
int paramCount = parseParams(valsLine, params, paramCounts, 256);
if (opCount == 0 || paramCount == 0) return 1;
Skiplist* obj = NULL;
printf("[");
for (int i = 0; i < opCount; i++) {
if (i > 0) printf(",");
if (strcmp(ops[i], "Skiplist") == 0) {
obj = skiplistCreate();
printf("null");
} else if (strcmp(ops[i], "add") == 0) {
skiplistAdd(obj, params[i][0]);
printf("null");
} else if (strcmp(ops[i], "search") == 0) {
printf("%s", skiplistSearch(obj, params[i][0]) ? "true" : "false");
} else if (strcmp(ops[i], "erase") == 0) {
printf("%s", skiplistErase(obj, params[i][0]) ? "true" : "false");
}
}
printf("]\n");
if (obj) skiplistFree(obj);
return 0;
}
Time & Space Complexity
Time Complexity
⏱️
O(log n)
Expected O(log n) for all operations due to probabilistic balancing through random heights
n
2n
✓ Linear Growth
Space Complexity
O(n)
Linear space for nodes, with expected O(n) total pointers across all levels
n
2n
⚡ Linearithmic Space
28.5K Views
MediumFrequency
~35 minAvg. Time
892 Likes
Ln 1, Col 1
Smart Actions
💡Explanation
AI Ready
💡 SuggestionTabto acceptEscto dismiss
// Output will appear here after running code
Code Editor Closed
Click the red button to reopen
Algorithm Visualization
Pinch to zoom • Tap outside to close
Test Cases
0 passed
0 failed
3 pending
Select Compiler
Choose a programming language
Compiler list would appear here...
AI Editor Features
Header Buttons
💡
Explain
Get a detailed explanation of your code. Select specific code or analyze the entire file. Understand algorithms, logic flow, and complexity.
🔧
Fix
Automatically detect and fix issues in your code. Finds bugs, syntax errors, and common mistakes. Shows you what was fixed.
💡
Suggest
Get improvement suggestions for your code. Best practices, performance tips, and code quality recommendations.
💬
Ask AI
Open an AI chat assistant to ask any coding questions. Have a conversation about your code, get help with debugging, or learn new concepts.
Smart Actions (Slash Commands)
🔧
/fix Enter
Find and fix issues in your code. Detects common problems and applies automatic fixes.
💡
/explain Enter
Get a detailed explanation of what your code does, including time/space complexity analysis.
🧪
/tests Enter
Automatically generate unit tests for your code. Creates comprehensive test cases.
📝
/docs Enter
Generate documentation for your code. Creates docstrings, JSDoc comments, and type hints.
⚡
/optimize Enter
Get performance optimization suggestions. Improve speed and reduce memory usage.
AI Code Completion (Copilot-style)
👻
Ghost Text Suggestions
As you type, AI suggests code completions shown in gray text. Works with keywords like def, for, if, etc.
Tabto acceptEscto dismiss
💬
Comment-to-Code
Write a comment describing what you want, and AI generates the code. Try: # two sum, # binary search, # fibonacci
💡
Pro Tip: Select specific code before using Explain, Fix, or Smart Actions to analyze only that portion. Otherwise, the entire file will be analyzed.