C 获取链表的节点号n

C 获取链表的节点号n,c,C,如果我有一个链接列表: first node -----> second node ------> third node ---> ? 我是否可以在不使用经典列表线性搜索算法的情况下显示第三个节点值(例如) 我尝试获取第n个节点: struct node* indexof( struct node* head, int i ) { int offset = (int)((char*)head->next - (char*)head); return ((

如果我有一个链接列表:

first node -----> second node ------> third node ---> ?
我是否可以在不使用经典列表线性搜索算法的情况下显示第三个节点值(例如)

我尝试获取第n个节点:

struct node* indexof( struct node* head, int i )
{
    int offset = (int)((char*)head->next - (char*)head);
    return ((struct node*)((char*)head + offset * i));
}

这取决于您的确切链表实现,但一般来说,不是。您必须遍历链表才能访问第n个元素

这是链表的一个特征,从某种意义上说,你可以用来计算数组或其他类似序列结构的偏移量的普通技巧将不起作用,因为你的单个列表元素不能保证以任何合理的方式排列在内存中,因此,为了检索第三个元素,您必须遵循
next
指针


您可以考虑在链表中提供固定时间索引访问的其他数据结构。

< P>链接列表的目的之一是能够轻松地添加和删除节点,成本很低。

您可以放弃该功能并使用有效负载指针数组,但它不再是一个链表(当可以通过算术增量轻松获得同一个节点时,拥有指向下一个节点的指针的目的是什么?)

例如,代替

struct
{
    struct node *next;
    void *payload;
    ...
} node;

node *root = NULL;
并为没有节点分配空间,您可以

typedef struct
{
    void *payload;
    ...
} node;
node *vector = NULL;
size_t vectorsize = 0;
并根据最初需要为尽可能多的节点分配空间,然后在需要时使用
realloc
扩展列表,并使用
memmove
通过将节点移回已删除节点之外的位置来删除节点。在添加或删除节点时,这会导致明显的性能损失。另一方面,第n个节点只是向量[n]

我重复一遍,这不再是一个链表:它可能是,无论您需要它做什么,它都可以通过指针数组而不是链表更好地完成

这提醒了我,您最好解释一下为什么需要直接寻址功能(“说明问题,不要问如何实现解决方案”):也可能您需要的是既不是数组也不是链表,但是,谁知道呢?可能是环缓冲区、堆栈、希尔或二叉树

在某些实现中,您甚至可以部署两个绑定结构,例如,您可能在第一阶段使用(双重?)链表,其中包含大量插入和删除,尤其是最近插入的数据;然后,构建并切换到第二阶段的指针数组,在该阶段中,需要由节点号驱动的直接寻址(将该数组用作列表节点地址的“缓存”):


听起来您选择了错误的数据结构。如果您想直接转到第n个,那么应该使用数组


如果不能做到这一点,那么以线性方式经历又有什么不好呢?必须在很长的链表上多次调用才能导致性能问题。

我已经实现了一个函数,但我不知道它是否正确
struct node*indexof(struct node*head,inti){int offset=(int)((char*)head->next-(char*)head);return((struct node*)((char*)head+offset*i));}
。一般来说,这不是你可以信赖的财产。如果它有时能工作,那完全是偶然的。如果你有一个双链接列表,你可以遍历一次,构建一个指向两个节点幂的指针列表。一旦你有了这些,你可以做更快的二进制搜索。如果您计划对“只读”数据结构进行多次搜索,那么开始时的线性成本可能是值得的。但是Gian建议选择不同的数据结构是正确的。函数的问题是节点在内存中可能不是相邻的。这意味着使用偏移量是行不通的。值得注意的是,数组很少能替代链表,因为调整(固定大小)数组大小的成本往往大于向链表中添加单个元素的成本。除了“数组”之外,还有其他更合适的替代品。
for (listsize = 0, scan = root; scan; scan = scan->next)
    listsize++;
if (NULL == (vector = (node *)malloc(listsize * sizeof(node))))
{
    // out of memory
    return EXIT_FAILURE;
}
for (listsize = 0, scan = root; scan; scan = scan->next)
    vector[listsize++] = scan;
// Now vector[i]->payload is the payload of the i-th node