You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言SkipList实现访问复杂度意外呈线性,求问题排查

自研跳表(SkipList)性能异常排查求助

我在部分程序中使用自研库提供的SkipList,近期发现其性能低于预期,于是编写了以下测试程序进行分析:

#include "usflib2.h"
#include <stdio.h>
#include <time.h>

uint64_t test(uint64_t);

int main() {
    uint64_t i, j, avg = 0;

    srand(time(NULL));
    printf("WARN: The skiplist must be made to return number of steps on access for this test to work.\n");

    for (i = 2; i < 10000000; i *= 2) {
        for (j = 0; j < 100; j++) {
            avg += test(i);
        }   

        printf("(%lu, %lu)\n", i, avg/100);
        fflush(stdout);
    }   
    return 0;
}

uint64_t test(uint64_t cycles) {
    uint64_t i;

    usf_skiplist *skp;
    skp = usf_skset(NULL, 0, USFNULL);

    for (i = 0; i < cycles; i++) {
        usf_skset(skp, i, USFDATAU(i));
    }   

    i = usf_skget(skp, i/2).u;

    /* Cleanup */
    usf_freesk(skp);

    return i;
}

测试结果显示,访问中间元素时时间复杂度呈线性增长(可视化后趋势明显)。

我多次检查仍未找到问题所在,怀疑是对SkipList的理解存在偏差。现将usf_skset()、usf_skget()的实现代码及头文件附上,请求协助排查问题:

usf_skset()实现

usf_skiplist *usf_skset(usf_skiplist *skiplist, uint64_t i, usf_data data) {
    int j;
    usf_skipnode *node, *next, **ptrs;
    usf_skipnode *position[USF_SKIPLIST_HEADSIZE];

    if (skiplist == NULL) { //创建跳表
        //分配跳表内存
        skiplist = malloc(sizeof(usf_skiplist));
        skiplist -> size = 1; //基础节点数

        node = malloc(sizeof(usf_skipnode)); //头节点

        //分配头节点的指针数组
        node -> nextnodes = calloc(sizeof(usf_skipnode **), USF_SKIPLIST_HEADSIZE);

        //设置基础数据
        node -> index = 0;
        node -> data = USFNULL;

        skiplist -> head = node;
    }

    //在跳表的索引i处插入数据
    node = skiplist -> head; //从头节点开始

    for (j = USF_SKIPLIST_HEADSIZE - 1; j >= 0; j--) {
        next = node -> nextnodes[j];

        while (next && next -> index <= i) {
            node = next;
            next = node -> nextnodes[j];
        }

        //记录当前层的停留位置
        position[j] = node;
    }

    if (node -> index == i) {
        //元素已存在,更新数据
        node -> data = data;
        return skiplist;
    }

    //创建并链接新节点
    node = malloc(sizeof(usf_skipnode));
    node -> index = i;
    node -> data = data;

    //随机决定新节点的层数
    for (j = 1; j < USF_SKIPLIST_HEADSIZE; j++)
        if (rand() & 1) break; //概率性终止层数提升

    ptrs = malloc(sizeof(usf_skipnode *) * j);

    for (j--; j >= 0; j--) {
        ptrs[j] = position[j] -> nextnodes[j]; //链接到下一个节点
        position[j] -> nextnodes[j] = node; //将前一个节点指向当前新节点
    }

    node -> nextnodes = ptrs;
    skiplist -> size++; //元素计数加1
    return skiplist;
}

usf_skget()实现(已修改为返回访问步数)

usf_data usf_skget(usf_skiplist *skiplist, uint64_t i) {
    uint64_t TEMP = 0; /* 临时变量:统计访问步数 */

    int j;
    usf_skipnode *node, *next;

    node = skiplist -> head;

    for (j = USF_SKIPLIST_HEADSIZE - 1; j >= 0; j--) {
        next = node -> nextnodes[j];

        while (next && next -> index <= i) {
            TEMP++; /* 统计步数 */

            /* 循环展开:每次循环处理两次迭代 */
            node = next;
            if ((next = node -> nextnodes[j]) == NULL || next -> index > i) break;

            node = next;
            next = node -> nextnodes[j];
        }

        if (node -> index == i) break;
    }

    return USFDATAU(TEMP); /* 临时返回步数 */
    if (node -> index != i) return USFNULL;

    return node -> data;
}

头文件usfskiplist.h

#ifndef USFSKIPLIST_H
#define USFSKIPLIST_H

#include <stdlib.h>
#include "usfdata.h"

#define USF_SKIPLIST_HEADSIZE 24

typedef struct usf_skipnode {
    struct usf_skipnode **nextnodes;
    usf_data data;
    uint64_t index;
} usf_skipnode;

typedef struct usf_skiplist {
    usf_skipnode *head;
    uint64_t size;
} usf_skiplist;

usf_skiplist *usf_skset(usf_skiplist *, uint64_t, usf_data);
usf_data usf_skget(usf_skiplist *, uint64_t);
usf_data usf_skdel(usf_skiplist *, uint64_t);
void usf_freesk(usf_skiplist *); 

#endif

内容的提问来源于stack exchange,提问作者lzg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 01:38:10