理解c中的链表式结构

时间:2013-11-20 06:14:11

标签: c linked-list

我无法理解代表链表结构的C代码。结构的骨架如下所示:

struct r{
   r *next;
   r **prev; 
   data *d;
}
struct r *rlist;

可以通过调用以下函数来填充rlist :(仅限骨架)

r* rcreate(data *d){
     struct r *a = xmalloc(sizeof(*r))
     a->d = d;
     a->next = rlist;
     a->prev = &rlist;
     if (rlist)
         rlist->prev = &a->next;
     rlist = a;
     return a;
}

如何使用此数据结构?例如如何遍历rlist?

编辑:这是删除链表中节点的功能

void rdestroy(struct r *a){
     if (a->next){
         a->next->prev = a->prev;
     }
     *a->prev = a->next;
      destroy(a->d); /* destroy is defined elsewhere */

}

4 个答案:

答案 0 :(得分:1)

没有充分的理由在该结构中使用r **。这是双链表。 因此,如果创建了这个东西,则将其分配

thisList = rcreate(“我的数据”)

现在你可以开始遍历它了 while(thisList-> next)   thisList = thisList-> next。 ...

答案 1 :(得分:1)

prev指针似乎只允许在一个方向上遍历列表,同时允许轻松删除(因为即使您无法轻松访问前一个元素),也可以访问next指针of previous element,并在删除节点时将其设置为新的正确值。

在没有看到其他相关功能的情况下,很难理解为什么这样做。我没有看到这样做,也不能立即想到任何真正有用的好处。

我认为这允许更简单的节点删除代码,因为节点不需要关心它是否是第一个,因为节点的prev指针对于在删除时需要修改的指针总是具有非NULL值本身。在当前节点之前插入的简单性相同。如果这些操作主导了使用模式,那么我认为这可能被视为次要优化,特别是在分支可能更昂贵的旧CPU中。

如何遍历列表

这是个问题,对吗?你只能以一种非常简单的方式向前遍历它,这里是遍历整个列表的for循环:

struct r *node;
for (node = rlist ; node ; node = node->next) {
    // assert that prev points to pointer, which should point to this node
    assert(*(node->prev) == node); 

    // use node
    printf("node at %p with data at %p\n", node, node->d);
}

插入功能示例

此示例插入函数演示了节点之前的插入如何不需要分支(未经测试):

struct r *rinsert(struct r *nextnode, data *d) {

     // create and initialize new node
     struct r *newnode = xmalloc(sizeof(struct r));
     newnode->d = d;
     newnode->next = nextnode;
     newnode->prev = nextnode->prev;

     // set next pointer of preceding node (or rlist) to point to newnode
     *(newnode->prev) = newnode;

     // set prev pointer of nextnode to point to next pointer of newnode
     nextnode->prev = &(newnode->next);

     return newnode;
}

答案 2 :(得分:0)

你的代码中有很多语法错误,可能是因为(如你所说)它是一个“骨架”,因此很难解析作者(无论是你或其他人)实际上是想要这个代码做什么的

简单(双重)链表结构如下所示:

struct node {
  struct node *next, *prev; // pointers to the adjacent list entries
  int data; // use whatever datatype you want
};

struct node *list = NULL; // the list starts empty

void add_entry(int new_data) {
  struct node *new_entry = malloc(sizeof(struct node));
  // note that in the above line you need sizeof the whole struct, not a pointer

  new_entry->data = new_data;
  new_entry->next = list; // will be added to the beginning of the list
  new_entry->prev = NULL; // no entries currently front of this one
  // in general a NULL pointer denotes an end (front or back) of the list

  list->prev = new_entry;
  list = new_entry; // now list points to this entry
  // also, this entry's "next" pointer points to what used to
  // be the start of the list
}

编辑:我会说,如果您希望我们帮助您了解一些较大程序的代码,您没有编写且无法修改,请以相应的格式发布相关代码至少是语法上的。正如其他人所说,例如,在您发布的代码中使用prev是难以理解的,并且不清楚(因为还有其他类似的令人困惑的语法问题)是否在原始代码中或是否是转录中引入的错误。

答案 3 :(得分:0)

杨,我不确定你的指针是多么的舒服。我建议看看其他一些链接列表实现,它可能就是这样做的。

看看这个Generic Linked List Implementation