在计算机科学中,跳表(Skip List)是一种概率性的数据结构,它可以在平均 O(log n) 的时间复杂度内完成查找、插入和删除操作。相比平衡树(如红黑树),跳表的实现更为简单,且性能接近。本教程将带你从零开始,用C语言跳表实现一个完整的跳表,并深入理解其原理。
跳表本质上是多层链表的组合。最底层(第0层)包含所有元素,形成一个有序链表。每一层向上,元素数量大约减少一半(通过随机抛硬币决定是否“提升”到上一层)。这样,在查找时可以从高层快速“跳跃”,大幅减少比较次数。
我们将逐步构建一个支持插入、查找和删除操作的跳表。
每个节点包含一个值和一个指针数组,指向各层的下一个节点:
#include <stdio.h>#include <stdlib.h>#include <time.h>#define MAX_LEVEL 16 // 最大层数typedef struct Node { int value; struct Node* forward[MAX_LEVEL];} Node;typedef struct SkipList { Node* header; int level; // 当前最大层数} SkipList; 辅助函数用于创建指定层数的新节点:
Node* createNode(int level, int value) { Node* node = (Node*)malloc(sizeof(Node)); node->value = value; for (int i = 0; i < level; i++) { node->forward[i] = NULL; } return node;} SkipList* createSkipList() { SkipList* list = (SkipList*)malloc(sizeof(SkipList)); list->level = 0; list->header = createNode(MAX_LEVEL, -1); // 头节点,值无意义 return list;} 使用“抛硬币”策略决定新节点应有多少层:
int randomLevel() { int level = 1; while ((rand() & 1) && level < MAX_LEVEL) { level++; } return level;} 插入时需记录每层的前驱节点,以便更新指针:
void insert(SkipList* list, int value) { Node* update[MAX_LEVEL]; Node* current = list->header; // 从最高层开始向下搜索 for (int i = list->level - 1; i >= 0; i--) { while (current->forward[i] != NULL && current->forward[i]->value < value) { current = current->forward[i]; } update[i] = current; } current = current->forward[0]; // 如果值已存在,不重复插入 if (current == NULL || current->value != value) { int newLevel = randomLevel(); if (newLevel > list->level) { for (int i = list->level; i < newLevel; i++) { update[i] = list->header; } list->level = newLevel; } Node* newNode = createNode(newLevel, value); for (int i = 0; i < newLevel; i++) { newNode->forward[i] = update[i]->forward[i]; update[i]->forward[i] = newNode; } }} int search(SkipList* list, int value) { Node* current = list->header; for (int i = list->level - 1; i >= 0; i--) { while (current->forward[i] != NULL && current->forward[i]->value < value) { current = current->forward[i]; } } current = current->forward[0]; if (current != NULL && current->value == value) { return 1; // 找到 } return 0; // 未找到} int main() { srand(time(NULL)); // 初始化随机种子 SkipList* list = createSkipList(); insert(list, 3); insert(list, 6); insert(list, 7); insert(list, 9); insert(list, 12); printf("Search 6: %s\n", search(list, 6) ? "Found" : "Not Found"); printf("Search 10: %s\n", search(list, 10) ? "Found" : "Not Found"); return 0;} 通过本教程,你已经掌握了如何用C语言高效查找并实现跳表的基本操作。跳表是一种优雅的数据结构,特别适合需要频繁插入、删除和查找的场景。虽然本文未实现删除操作,但你可以基于插入逻辑自行扩展。
记住,跳表的关键在于跳表插入删除教程中提到的“多层指针”和“随机层数”机制。掌握这些,你就能轻松应对面试或实际项目中的高性能需求。
提示:实际项目中可考虑内存池优化,避免频繁 malloc/free。
本文由主机测评网于2025-12-08发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/2025124543.html