精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

C語言數據結構之跳表詳解

嵌入式開發愛好者 ? 來源:嵌入式開發愛好者 ? 作者:嵌入式開發愛好者 ? 2023-12-29 09:32 ? 次閱讀

大家好,今天分享一篇C語言數據結構相關的文章--跳表。

1. 什么是跳表

跳表是鏈表+索引的一種數據結構 ,是以空間換取時間的方式,關于跳表參考:

ed86329c-a59a-11ee-8b88-92fbcf53809c.png

2. 跳表概念

跳表在原有鏈表的基礎上,增加索引,從而可以進行二分查找,提高搜尋效率。

原始鏈表

Head ——> 1 ——> 8 ——> 12 ——> 23 ——> 55 ——> NULL

新增了索引的鏈表(跳表)

Head2 ————————> 8 ———————————————————————> NULL 
Head1 ————————> 8 —————————> 23 —————————> NULL 
Head0 ——> 1 ——> 8 ——> 12 ——> 23 ——> 55 ——> NULL

Head0 , Head1 , Head2 上都是真實的節點,這就是以空間換取時間

例如算上Head, 元素數據一共有 6 個,而添加索引后,元素一共有 11 個

3. 跳表增刪查規則

3.1 跳表數據節點

數據節點可以和鏈表節點一致 ,也可以定義如下節點,除了數據外,有指針指向 前一個/后一個/上一個/下一個 節點,以便后續查找操作。

typedef struct {
        int data;
        struct Node *next; // 后一個節點
        struct Node *last; // 前一個節點
        struct Node *up; // 上一個節點
        struct Node *down; // 下一個節點
} Node;

3.2 跳表初始化

當跳表有多少層的時候,應當建立多少個頭結點,例如: 跳表為3層

Head2 ——> NULL
Head1 ——> NULL
Head0 ——> NULL

3.3 查找

刪除/新增 都會進行查詢才操作,無非是刪除/新增索引而已。

例如有如下數據

Head2 —————————————————————> 23 —————————> NULL 
Head1 ————————> 8 —————————> 23 —————————> NULL 
Head0 ——> 1 ——> 8 ——> 12 ——> 23 ——> 55 ——> NULL

要查找13這個節點

去除無效層 例如:Head2后面第一個節點的數據23, 而23大于13, 所以Head2沒有數據匹配查詢,故需要跳到下面一層,至Head1上進行查詢。 查詢至Head0層 去除無效層后數據進入了Head1, 在Head1上進行匹配,當匹配到23時,23大于13,將23標記為 查詢結束點,對23的上一個節點 8 進行 向下指針操作,進入Head0層的8節點。 查找實際數據Head0層的8 進行查找,直至查詢結束標記點(head1 23), 查詢的數據分別為 8 , 12 ,23 查詢結束,未找到數據。 3.4 新增

新增操作需要記錄索引尋址過程,以便后續新增索引。

頭結點插入 頭結點插入一定是去除無效層至Head0 , 且Head0的第一個節點都比插入節點要大的情況下 例如: 如下跳表,插入 2

Head2 —————————————————————> 23 —————————> NULL 
Head1 ————————> 8 —————————> 23 —————————> NULL 
Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> NULL

尾結點插入

頭結點插入一定是去除無效層至Head0 , 且Head0的第一個節點都比插入節點要小,直至NULL節點的情況下

例如:

如下跳表,插入 65

Head2 —————————————————————> 23 —————————> NULL 
Head1 ————————> 8 —————————> 23 —————————> NULL 
Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> NULL

中間節點插入

除開以上2種情況,其余情況為 中間節點插入

新增索引

拋硬幣的方法,當數據量達到一定規模的時候,一定是趨近于 50%的。

所以跳表會越來越趨向于如下形式

    3
    3       7
1   3   5   7   9
1 2 3 4 5 6 7 8 9

判斷是否需要新增索引,采取拋硬幣的方法來判斷,即: 隨機數 取余 為 0 則需要新增,否則不需要。

例如如下跳表,插入 65

Head2 —————————————————————> 23 —————————> NULL 
Head1 ————————> 8 —————————> 23 —————————> NULL 
Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> NULL
尋址應該為
Head2: 23
Head1: 23 元素數據插入后為
Head2 —————————————————————> 23 ———————————————> NULL 
Head1 ————————> 8 —————————> 23 ———————————————> NULL 
Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> 65 —> NULL  

當插入65節點后,若判斷需要索引的時候,則先為 Head1 添加索引,添加位置為 尋址地址之后,寄 Head1: 23

Head2 —————————————————————> 23 ———————————————> NULL 
Head1 ————————> 8 —————————> 23 —————————> 65 —> NULL 
Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> 65 —> NULL  

繼續判斷,若不需要添加索引,則插入結束

若還需要添加索引,則繼續上述操作,直至 索引層 達到最高層

3.5 刪除

刪除首先是查找操作【3.3 查找】

若未找到該節點,則刪除失敗

若找到了該節點,則應當提到該數據最高索引層,再從高到低刪除

例如:

如下跳表,刪除 23

Head2 —————————————————————> 23 ———————————————> NULL 
Head1 ————————> 8 —————————> 23 —————————> 65 —> NULL 
Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> 65 —> NULL  

找到 Head0 23 后,應該向上找到 Head2 23 ,然后從高向低刪除,若刪除后,該索引沒有數據了,則索引層減1

則刪除Head2 23 后數據如下

Head1 ————————> 8 —————————> 23 —————————> 65 —> NULL 
Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> 65 —> NULL  
刪除Head1 23 后數據如下
Head1 ————————> 8 ———————————————————————> 65 —> NULL 
Head0 ——> 3 ——> 8 ——> 12 ——> 23 ——> 55 ——> 65 —> NULL 
刪除Head0 23后數據如下
Head1 ————————> 8 ————————————————> 65 —> NULL 
Head0 ——> 3 ——> 8 ——> 12 ——> 55 ——> 65 —> NULL 

4. 代碼

skipList.c

# include 
# include 
# include 

int MaxLevel = 8; // 最大層數
int currLevel = 0; // 當前層數

// 數據節點
typedef struct {
        int data;
        struct Node *next;
        struct Node *last;
        struct Node *up;
        struct Node *down;
} Node;

// 記錄索引尋址過程
typedef struct {
        int level;
        struct Node *node;
} skipStep;

// 判斷是否需要新增索引, 拋硬幣
bool randNum() {
        if(0 == (rand() % 2))
                return true;

        return false;
}

// 新增節點
bool add(Node *SL[] , int data) {

        printf("新增節點: %d
",data);
        int level = currLevel;

        Node *Head = NULL;
        Node *tmp = NULL;
        Node *last = NULL;

        // 初始化索引 數據為 Head 地址
        skipStep steps[MaxLevel];
        int i;
        for (i=0;inext;

        while ((level > 0) && (data < tmp->data)) {
                level--;
                Head = SL[level];
                tmp = Head->next;
        }

        // 根據索引尋找Head0數據節點
        while ((level > 0)) {

                while (tmp != NULL) {
                        if (data < tmp->data) {
                                steps[level].level = level;
                                if (NULL != last) 
                                        steps[level].node = last;
                                tmp = last->down;
                                level--;
                                break;
                        }

                        last = tmp;
                        tmp = tmp->next;
                }
                if (NULL == tmp) {
                        steps[level].level = level;
                        if (NULL != last) 
                                steps[level].node = last;
                        tmp = last->down;
                        level--;

                }
        }

        // Head0 數據合適的節點
        while (tmp != NULL) {
                if (data < tmp->data) {
                        break;
                }
                last = tmp;
                tmp = tmp->next;
        }

        // 新增節點
        Node *newData = (Node *)malloc(sizeof(Node));
        newData->data = data;
        newData->up = NULL;
        newData->down = NULL;
        newData->last = NULL;
        newData->next = NULL;

        int k = 0;

        // Head0 插入原始數據
        if (NULL == last ) {
                // 頭結點

                Head = SL[0];
                Node *headNext = Head->next;
                if (NULL != headNext) {
                        newData->next = headNext;
                        headNext->last = newData;

                        newData->last = Head;


                } 

                Head->next = newData;
                newData->last = Head;


        } else if ( NULL == tmp) {
                // 尾節點
                last->next = newData;
                newData->last = last;


        } else {
                // 中間節點
                newData->next = tmp;
                tmp->last = newData;

                newData->last = last;
                last->next = newData;
        }

        // 構建索引
        while (randNum()) {
                k++;
                if (k >= MaxLevel) break;

                // 新增索引數據
                Node *newIndex = (Node *)malloc(sizeof(Node));
                newIndex->data = data;
                newIndex->up = NULL;
                newIndex->down = NULL;
                newIndex->next = NULL;
                newIndex->last = NULL;

                // 建立上下級關系
                newIndex->down = newData;
                newData->up = newIndex;

                Node *node = steps[k].node;

                // node->next
                Node *nextIndex = node->next;


                node->next = newIndex;
                newIndex->last = node;

                newIndex->next = nextIndex;
                if (NULL != nextIndex) 
                        nextIndex->last = newIndex;

                newData = newIndex;

                // 判斷是否需要新增索引層數
                if (k > currLevel) 
                        currLevel = k;
        }
}


// 初始化頭結點
Node *initSkipList(Node *skipList[]) {
        int i;
        for (i=0;idata = -1-i;
                newHead->down = NULL;
                newHead->up = NULL;
                newHead->next = NULL;
                newHead->last = NULL;

                skipList[i] = newHead;


        }
        return skipList;
}

// 打印跳表數據
void PrintSkipList(Node *SL[]) {
        if (NULL == SL) {
                return;
        };

        int level = currLevel;
        //int level = MaxLevel;

        int i;
        for (i=level;i>=0;i--) {
                Node *Head = SL[i];

                Node *tmp = Head->next;
                printf("第%d層		",i);
                while (NULL != tmp) {
                        printf(" %d	",tmp->data);

                        tmp = tmp->next;
                }
                printf("
");
        }
}

// 查詢數據
Node *query(Node *SL[] , int data) {
        printf("查詢數據: %d
",data);

        int level = currLevel;

        Node *Head = NULL;
        Node *tmp = NULL;
        Node *last = NULL;

        Head = SL[level];
        tmp = Head->next;
        int endQuery = -1;

        // 篩除無效層
        while ((level > 0) && (data < tmp->data)) {
                level--;
                endQuery = tmp->data;
                Head = SL[level];
                tmp = Head->next;
        }

        // 根據索引定位到Head0層
        while ((level > 0 )) {

                while (tmp != NULL) {
                        if (data < (tmp->data)) {
                                level--;
                                endQuery = tmp->data;
                                tmp = last->down;
                                break;
                        }

                        last = tmp;
                        tmp = tmp->next;
                }
                if (NULL == tmp) {
                        tmp = last->down;
                        endQuery = -1;
                        level--;
                }

        }

        // 查詢實際數據
        while (NULL != tmp) {
                if (endQuery != -1)
                        if (tmp->data > endQuery) {
                                        tmp = NULL;
                                        break;
                        }
                if (tmp->data == data) {
                        break;
                }
                tmp = tmp->next;
        }
        // 返回查詢的數據節點,若沒有查詢到,應當返回NULL ,否則返回實際的地址
        return tmp;
}

// 刪除數據
bool del(Node *SL[],int data) {
        printf("刪除數據: %d
",data);

        // 找到節點地址
        Node *tmp = query(SL,data);

        if (NULL == tmp) {
                printf("未找到節點,刪除失敗
");
                return false;
        }
        int level = 0;
        Node *t_last = NULL;
        Node *t_next = NULL;


        // 找到該數據最高索引
        while (NULL != tmp->up) {
                level++;
                tmp = tmp->up;
        }

        // 由上至下刪除索引/數據
        while (tmp != NULL) {
                t_last = tmp->last;
                t_next = tmp->next;

                Node *t_down = tmp->down;

                if (t_last == NULL) {
                        printf("上一個節點不可能為空,刪除失敗,層數: %d
",level);
                        return false;
                }

                t_last->next = t_next;

                if (NULL != t_next)
                        t_next->last = t_last;
                else
                        t_last->next = NULL;

                if ((t_last == SL[level]) && (NULL == t_next)) {
                        currLevel--;

                }
                free(tmp);

                tmp = t_down;
                level--;
        }

        return true;


}

int main() {

        Node *SL[MaxLevel];

        Node *skipList = initSkipList(SL);
        if (NULL == SL) {
                printf("skipList 申請失敗
");
                return -1;
        }

        // 測試新增
        int num[] = {1,3,2,10,8,9,22,30,29,120,99,78,55,76,21};
        int i;
        for (i=0;i

執行結果

# gcc skipList.c -w -g
# ./a.out 
新增節點: 1
新增節點: 3
新增節點: 2
新增節點: 10
新增節點: 8
新增節點: 9
新增節點: 22
新增節點: 30
新增節點: 29
新增節點: 120
新增節點: 99
新增節點: 78
新增節點: 55
新增節點: 76
新增節點: 21
第5層            99
第4層            99
第3層            76      99
第2層            9       76      99
第1層            3       9       29      30      76      78      99
第0層            1       2       3       8       9       10      21      22      29      30      55      76      78      99      120
刪除數據: 99
查詢數據: 99
刪除數據: 9
查詢數據: 9
刪除數據: 78
查詢數據: 78
刪除數據: 55
查詢數據: 55
刪除數據: 3
查詢數據: 3
刪除數據: 1
查詢數據: 1
刪除數據: 28
查詢數據: 28
未找到節點,刪除失敗
刪除數據: 78
查詢數據: 78
未找到節點,刪除失敗
第3層            76
第2層            76
第1層            29      30      76
第0層            2       8       10      21      22      29      30      76      120

#

審核編輯:湯梓紅

(num)>;i++)>;i++)>
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • C語言
    +關注

    關注

    180

    文章

    7575

    瀏覽量

    134027
  • 代碼
    +關注

    關注

    30

    文章

    4670

    瀏覽量

    67764
  • 數據結構
    +關注

    關注

    3

    文章

    568

    瀏覽量

    40030

原文標題:嵌入式中一文搞定C語言數據結構--跳表

文章出處:【微信號:嵌入式開發愛好者,微信公眾號:嵌入式開發愛好者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    單片機 數據結構 算法 C語言 資料

    單片機 數據結構算法C語言資料
    發表于 02-20 17:00

    C語言數據結構

    目錄個人介紹筆試單選題C語言數據結構計算機與操作系統網絡通信填空題C語言數據結構網絡通信問答題
    發表于 08-06 07:10

    數據結構教程,下載

    1. 數據結構的基本概念 2. 算法與數據結構3. C語言數據類型及其算法描述要點4. 學習算法與
    發表于 05-14 17:22 ?0次下載
    <b class='flag-5'>數據結構</b>教程,下載

    數據結構教學軟件

    數據結構教學軟件:有C語言,pascal語言兩種。
    發表于 10-24 12:15 ?51次下載
    <b class='flag-5'>數據結構</b>教學軟件

    數據結構 C語言 》電子教案免費下載

    數據結構 C語言 》電子教案免費下載 轉變二、              聲明位置的轉變 &
    發表于 03-01 15:07 ?0次下載

    C語言入門教程-動態數據結構

    動態數據結構 動態數據結構可以根據需要,從稱之為堆的內存空間上分配和釋放內存。動態數據結構C程序中極其重要,因為通過動態數據結構,程序員
    發表于 07-29 11:51 ?1096次閱讀

    數據結構(C#語言版)

    電子發燒友網站提供《數據結構(C#語言版).txt》資料免費下載
    發表于 10-04 22:49 ?0次下載

    數據結構與算法分析(C語言版)

    電子發燒友網站提供《數據結構與算法分析(C語言版).txt》資料免費下載
    發表于 11-28 11:05 ?0次下載

    數據結構C語言版)

    電子發燒友網站提供《數據結構C語言版).txt》資料免費下載
    發表于 08-07 11:45 ?0次下載

    數據結構C++語言描述

    數據結構c的電子書,希望任何讀者下載學習。
    發表于 12-22 17:44 ?0次下載

    數據結構-C語言描述(陳慧南)

    介紹數據結構C語言藐視的基本知識 有需要的朋友下來看看
    發表于 12-24 10:49 ?0次下載

    數據結構與算法

    全國C語言考試公共基礎知識點——數據結構與算法,該資料包含了有關數據結構與算法的全部知識點。
    發表于 03-30 14:27 ?0次下載

    二級C語言考試算法與數據結構相關資料下載

    二級C語言考試算法與數據結構
    發表于 03-19 17:33 ?13次下載

    數據結構與算法分析—C語言描述

    數據結構與算法分析:C語言描述》曾被評為20世紀頂尖的30部計算機著作之一,作者在數據結構和算法分析方面卓有建樹,他的數據結構和算法分析的
    發表于 10-14 08:00 ?17次下載
    <b class='flag-5'>數據結構</b>與算法分析—<b class='flag-5'>C</b><b class='flag-5'>語言</b>描述

    數據結構與算法分析——Java語言描述

    數據結構與算法分析——Java語言描述說明。
    發表于 05-31 14:25 ?22次下載