C語言跳表(Skip List)算法:數據世界的“時光穿梭機”

? ? ? ? 在數據結構算法中,有一種算法猶如“時空穿梭機”,能在瞬間跨越層層障礙,直擊目標——它就是跳表算法。下面,就讓我們一起揭開跳表算法的神秘面紗,通過實例探究其高效與魅力。

目錄

一、跳表算法是什么?

二、實例解析

1、跳表的構建

2、查找過程

三、跳表算法的優點

四、跳表——C語言實現

1、常規鏈表查找

2、跳表查找

一、跳表算法是什么?

? ? ? ? 跳表,顧名思義,是一種能夠“跳過”某些節點進行搜索的鏈表。它通過再鏈表的基礎上增加多級索引,實現了對數據的快速定位、插入與刪除。想象一下,再一條長長的隊伍中,你能直接跳到接近目標的位置,是不是能縮短搜索該目標的時間,從而大大提高代碼運行效率。

二、實例解析

? ? ? ? 假設有一個有序的鏈表,存儲了數字1到10。現在,需要查找數字7.在沒有跳表的情況下,可能需要從頭開始,一步步遍歷到7。但是有了跳表,一切都將變得不同。

1、跳表的構建

? ? ? ? 首先,要為這個鏈表構建一個跳表。跳表分為多層,每一層都是下面一層的部分節點建立的索引。比如:

層3:4,8

層2:2,4,6,8,10

層1:1,2,3,4,5,6,7,8,9,10

2、查找過程

? ? ? ? 現在,開始查找數據7:

? ? ? ? 從層3開始查找,首先比較4和7。由于4比7小,就繼續向右查找,直至比較到8,仍未找到7,于是便下降到層2。

? ? ? ? 在層2比較6和7。6仍然小于7,但接近查找目標。繼續向右查找,發現8大于7,于是再次下降一層,到達層1。

? ? ? ? 在層1,直接定位到6,便可輕松查找到值7。

? ? ? ? 通過這個實例可以看到,跳表通過多級索引,實現了對數據的快速定位,大大減少了查找的時間復雜度。但代價是占用更多的空間。典型的空間換時間

三、跳表算法的優點

高效性:跳表的查找、插入和刪除操作的平均時間復雜度都是O(log n),媲美平衡樹結構。

簡單性:相對于紅黑樹等復雜的數據結構,跳表的實現更為簡單,易于理解和維護。

隨機性:跳表的隨機性保證了其性能的穩定性,避免了極端情況下的性能下降。

四、跳表——C語言實現

1、常規鏈表查找

#include <stdio.h>
#include <stdlib.h>// 跳表節點定義
typedef struct SkipListNode {int value;struct SkipListNode *next;struct SkipListNode *skip;
} SkipListNode;// 創建跳表節點
SkipListNode* createSkipListNode(int value) {SkipListNode* node = (SkipListNode*)malloc(sizeof(SkipListNode));node->value = value;node->next = NULL;node->skip = NULL;return node;
}// 插入節點到跳表
void insertSkipList(SkipListNode** head, int value) {SkipListNode* newNode = createSkipListNode(value);if (*head == NULL) {*head = newNode;return;}SkipListNode* current = *head;SkipListNode* skipPrev = NULL;// 尋找插入位置while (current != NULL && current->value < value) {skipPrev = current;current = current->next;}// 插入節點newNode->next = current;if (skipPrev != NULL) {skipPrev->next = newNode;} else {*head = newNode;}// 更新跳過指針if (skipPrev != NULL && skipPrev->skip != NULL && skipPrev->skip->value < value) {newNode->skip = skipPrev->skip->next;skipPrev->skip->next = newNode;}
}// 查找節點
SkipListNode* findSkipList(SkipListNode* head, int value) {SkipListNode* current = head;while (current != NULL) {if (current->value == value) {return current;} else if (current->skip != NULL && current->skip->value <= value) {current = current->skip;} else {current = current->next;}}return NULL;
}// 打印跳表
void printSkipList(SkipListNode* head) {SkipListNode* current = head;while (current != NULL) {printf("%d ", current->value);if (current->skip != NULL) {printf("(skip to %d) ", current->skip->value);}current = current->next;}printf("\n");
}// 主函數
int main() {SkipListNode* head = NULL;// 插入數據insertSkipList(&head, 3);insertSkipList(&head, 7);insertSkipList(&head, 6);insertSkipList(&head, 9);insertSkipList(&head, 12);insertSkipList(&head, 19);insertSkipList(&head, 25);insertSkipList(&head, 30);// 打印跳表printf("Skip List: ");printSkipList(head);// 查找數據int valueToFind = 19;SkipListNode* foundNode = findSkipList(head, valueToFind);if (foundNode != NULL) {printf("Value %d found in the skip list.\n", valueToFind);} else {printf("Value %d not found in the skip list.\n", valueToFind);}return 0;
}

2、跳表查找

#include <stdio.h>
#include <stdlib.h>
#include <time.h>#define MAXLEVEL 3 // 假設跳表的最大層級為3// 跳表節點定義
typedef struct SkipListNode {int value;struct SkipListNode *forward[MAXLEVEL]; // 指向不同層級的下一個節點
} SkipListNode;// 創建跳表節點
SkipListNode* createSkipListNode(int level, int value) {SkipListNode* newNode = (SkipListNode*)malloc(sizeof(SkipListNode));newNode->value = value;for (int i = 0; i < level; i++) {newNode->forward[i] = NULL;}return newNode;
}// 隨機生成節點的層級
int randomLevel() {int level = 1;while ((rand() & 0xFFFF) < (0.5 * 0xFFFF)) {level++;if (level == MAXLEVEL) break;}return level;
}// 插入節點到跳表
void insertSkipList(SkipListNode **head, int value) {SkipListNode *update[MAXLEVEL];SkipListNode *current = *head;// 從最高層開始,找到每層中插入位置的前一個節點for (int i = MAXLEVEL - 1; i >= 0; i--) {while (current->forward[i] != NULL && current->forward[i]->value < value) {current = current->forward[i];}update[i] = current;}// 隨機決定新節點的層級int level = randomLevel();// 創建新節點SkipListNode *newNode = createSkipListNode(level, value);// 將新節點插入到跳表中for (int i = 0; i < level; i++) {newNode->forward[i] = update[i]->forward[i];update[i]->forward[i] = newNode;}
}// 查找節點
int findSkipList(SkipListNode *head, int value) {SkipListNode *current = head;int count = 0;int ncount = 0;for (int i = MAXLEVEL - 1; i >= 0; i--) {count ++ ;while (current->forward[i] != NULL && current->forward[i]->value < value) {current = current->forward[i];ncount ++ ;printf("ncount %d .\n", ncount);}count += ncount;printf("count %d .\n", count);ncount = 0;if(current->forward[i] != NULL && current->forward[i]->value == value ){return count; // 找到值,返回查找次數}}return -1; // 未找到值
}// 打印跳表
void printSkipList(SkipListNode *head) {for (int i = MAXLEVEL - 1; i >= 0; i--) {SkipListNode *current = head->forward[i];printf("Level %d: ", i);while (current != NULL) {printf("%d ", current->value);current = current->forward[i];}printf("\n");}
}int main() {srand((unsigned)time(NULL)); // 初始化隨機數生成器// 創建跳表頭節點SkipListNode *head = createSkipListNode(MAXLEVEL, -1);// 插入數據insertSkipList(&head, 3);insertSkipList(&head, 6);insertSkipList(&head, 7);insertSkipList(&head, 9);insertSkipList(&head, 12);insertSkipList(&head, 19);insertSkipList(&head, 25);insertSkipList(&head, 29);// 打印跳表printSkipList(head);// 查找數據int valueToFind = 7;int searchCount = findSkipList(head, valueToFind);if (searchCount != -1) {printf("Number of steps taken to find the value %d: %d\n", valueToFind, searchCount);} else {printf("Value %d not found in the skip list.\n", valueToFind);}valueToFind = 29;searchCount = findSkipList(head, valueToFind);if (searchCount != -1) {printf("Number of steps taken to find the value %d: %d\n", valueToFind, searchCount);} else {printf("Value %d not found in the skip list.\n", valueToFind);}// TODO: 實現刪除操作以及內存釋放return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/899967.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/899967.shtml
英文地址,請注明出處:http://en.pswp.cn/news/899967.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2023第十四屆藍橋杯大賽軟件賽省賽C/C++ 大學 B 組(真題題解)(C++/Java題解)

記錄刷題的過程、感悟、題解。 希望能幫到&#xff0c;那些與我一同前行的&#xff0c;來自遠方的朋友&#x1f609; 大綱&#xff1a; 1、日期統計-&#xff08;解析&#xff09;-暴力dfs&#xff08;&#x1f609;藍橋專屬 2、01串的熵-&#xff08;解析&#xff09;-不要chu…

批量將文本文件轉換為 Word/PDF/Excel/圖片等其它格式

工作中我們經常會接觸到各種格式的文本文檔&#xff0c;比如說 txt 記事本文件、json文件、HTML格式文件等等。通常也會需要將文本文件轉換為其他的格式&#xff0c;比如說將文本文件轉換為 word 格式、PDF格式或者圖片格式等等。當我們想要對文本文件格式進行批量轉換的時候&a…

Java常用工具算法-2--加密算法1--對稱加密算法(推薦AES算法)

1、定義與核心原理 定義&#xff1a;加密和解密使用相同密鑰的算法。工作流程&#xff1a; 秘鑰協商&#xff1a;雙方需提前通過安全信道共享密鑰。加密過程&#xff1a;發送方用密鑰對明文加密&#xff0c;生成密文。解密過程&#xff1a;接收方用相同密鑰對密文解密&#xf…

WPS宏開發手冊——Excel常用Api

目錄 系列文章4、Excel常用Api4.1、判斷是否是目標工作excel4.2、獲取源工作表和目標工作表的引用4.3、獲取單元格的值4.4、設置單元格的值4.5、合并單元格4.6、獲取源范圍4.7、獲取源范圍行數4.8、通過源來獲取單元格的值4.9、設置單元格的背景顏色4.10、設置單元格的文字顏色…

安徽京準:GPS北斗衛星校時服務器助力大數據云計算

安徽京準&#xff1a;GPS北斗衛星校時服務器助力大數據云計算 安徽京準&#xff1a;GPS北斗衛星校時服務器助力大數據云計算 GPS北斗衛星校時服務器在大數據與云計算系統中發揮著關鍵作用&#xff0c;其通過提供高精度、高可靠的時間同步服務&#xff0c;解決了分布式系統的核…

音視頻 ColorSpace色彩空間詳解

前言 基于前篇介紹YUV格式,本文繼續介紹另一個重要概念顏色空間,又叫色彩空間;主要用于在音視頻開發中的色彩空間轉換。 色彩空間Color Space 色彩空間由色彩模型和色域共同定義。當色彩模型與特定的描述相關聯以后,就稱為色彩空間。 色彩模型Color Model 色彩模型Col…

高效定位 Go 應用問題:Go 可觀測性功能深度解析

作者&#xff1a;古琦 背景 自 2024 年 6 月 26 日&#xff0c;阿里云 ARMS 團隊正式推出面向 Go 應用的可觀測性監控功能以來&#xff0c;我們與程序語言及編譯器團隊攜手并進&#xff0c;持續深耕技術優化與功能拓展。這一創新性的解決方案旨在為開發者提供更為全面、深入且…

構造超小程序

文章目錄 構造超小程序1 編譯器-大小優化2 編譯器-移除 C 異常3 鏈接器-移除所有依賴庫4 移除所有函數依賴_RTC_InitBase() _RTC_Shutdown()__security_cookie __security_check_cookie()__chkstk() 5 鏈接器-移除清單文件6 鏈接器-移除調試信息7 鏈接器-關閉隨機基址8 移除異常…

大語言模型開發框架——LangChain

什么是LangChain LangChain是一個開發由語言模型驅動的應用程序的框架&#xff0c;它提供了一套工具、組件和接口&#xff0c;可以簡化構建高級語言模型應用程序的過程。利用LangChain可以使應用程序具備兩個能力&#xff1a; 上下文感知 將語言模型與上下文&#xff08;提示…

自動化釋放linux服務器內存腳本

腳本說明 使用Linux的Cron定時任務結合Shell腳本來實現自動化的內存釋放。 腳本用到sync系統命令 sync的作用&#xff1a;sync 是一個 Linux 系統命令&#xff0c;用于將文件系統緩存中的數據強制寫入磁盤。 在你執行reboot、poweroff、shutdown命令時&#xff0c;系統會默認執…

Python Websockets庫深度解析:構建高效的實時Web應用

引言 在現代Web開發中&#xff0c;實時通信已經成為許多應用的核心需求。無論是聊天應用、在線游戲、金融交易平臺還是協作工具&#xff0c;都需要服務器和客戶端之間建立持久、雙向的通信通道。傳統的HTTP協議由于其請求-響應模式&#xff0c;無法有效滿足這些實時交互需求。…

【實用技巧】電腦重裝后的Office下載和設置

寫在前面&#xff1a;本博客僅作記錄學習之用&#xff0c;部分圖片來自網絡&#xff0c;如需引用請注明出處&#xff0c;同時如有侵犯您的權益&#xff0c;請聯系刪除&#xff01; 文章目錄 前言下載設置總結互動致謝參考目錄導航 前言 在數字化辦公時代&#xff0c;Windows和…

Node.js 技術原理分析系列 —— Node.js 調試能力分析

Node.js 技術原理分析系列 —— Node.js 調試能力分析 Node.js 作為一個強大的 JavaScript 運行時環境,提供了豐富的調試能力,幫助開發者診斷和解決應用程序中的問題。本文將深入分析 Node.js 的調試原理和各種調試技術。 1. Node.js 調試原理 1.1 V8 調試器集成 Node.js…

【圖論】最短路徑問題總結

一圖勝千言 單源最短路徑 正權值 樸素Dijkstra dijkstra算法思想是維護一個永久集合U&#xff0c;全部點集合V。 循環n -1次 從源點開始&#xff0c;在未被訪問的節點中&#xff0c;選擇距離源點最近的節點 t。 以節點 t 為中間節點&#xff0c;更新從起點到其他節點的最短…

【最佳實踐】win11使用hyper-v安裝ubuntu 22/centos,并配置固定ip,掃坑記錄

文章目錄 場景查看本機的win11版本啟用hyper-vhyper-v安裝ubuntu22虛擬機1.準備好個人的 iso文件。2. hyper-v 快速創建3.編輯設置分配內存自定義磁盤位置設置磁盤大小連接網絡修改虛擬機名稱自定義檢查點位置 和智能分頁件位置虛擬機第一次連接給ubuntu22配置固定ip遇到過的坑…

自然語言處理(25:(終章Attention 1.)Attention的結構?)

系列文章目錄 終章 1&#xff1a;Attention的結構 終章 2&#xff1a;帶Attention的seq2seq的實現 終章 3&#xff1a;Attention的評價 終章 4&#xff1a;關于Attention的其他話題 終章 5&#xff1a;Attention的應用 目錄 系列文章目錄 前言 Attention的結構 一.seq…

Git 命令大全:通俗易懂的指南

Git 命令大全&#xff1a;通俗易懂的指南 Git 是一個功能強大且廣泛使用的版本控制系統。對于初學者來說&#xff0c;它可能看起來有些復雜&#xff0c;但了解一些常用的 Git 命令可以幫助你更好地管理代碼和協作開發。本文將介紹一些常用的 Git 命令&#xff0c;并解釋它們的…

基于yolov11的棉花品種分類檢測系統python源碼+pytorch模型+評估指標曲線+精美GUI界面

【算法介紹】 基于YOLOv11的棉花品種分類檢測系統是一種高效、準確的農作物品種識別工具。該系統利用YOLOv11深度學習模型&#xff0c;能夠實現對棉花主要品種&#xff0c;包括樹棉&#xff08;G. arboreum&#xff09;、海島棉&#xff08;G. barbadense&#xff09;、草棉&a…

論文:Generalized Category Discovery with Clustering Assignment Consistency

論文下載&#xff1a; https://arxiv.org/pdf/2310.19210 一、基本原理 該方法包括兩個階段:半監督表示學習和社區檢測。在半監督表示學習中&#xff0c;使用了監督對比損失來充分地推導標記信息。此外&#xff0c;由于對比學習方法與協同訓練假設一致&#xff0c;研究引入了…

Java高級JVM知識點記錄,內存結構,垃圾回收,類文件結構,類加載器

JVM是Java高級部分&#xff0c;深入理解程序的運行及原理&#xff0c;面試中也問的比較多。 JVM是Java程序運行的虛擬機環境&#xff0c;實現了“一次編寫&#xff0c;到處運行”。它負責將字節碼解釋或編譯為機器碼&#xff0c;管理內存和資源&#xff0c;并提供運行時環境&a…