C 没有自指结构的帮助,是否可以建立一个链表?
没有自指结构的帮助,是否可以建立一个链表?也就是说,像这样使用指针:C 没有自指结构的帮助,是否可以建立一个链表?,c,data-structures,singly-linked-list,C,Data Structures,Singly Linked List,没有自指结构的帮助,是否可以建立一个链表?也就是说,像这样使用指针: struct list{ int data; int *nxt; }; 而不是 struct list{ int data; struct list *nxt; }; 您可以了解一下链表是如何在Linux内核中实现的 与经典链表相比: struct my_list{ void *myitem; struct my_list *next; struct my_list
struct list{
int data;
int *nxt;
};
而不是
struct list{
int data;
struct list *nxt;
};
您可以了解一下链表是如何在Linux内核中实现的 与经典链表相比:
struct my_list{
void *myitem;
struct my_list *next;
struct my_list *prev;
};
在linux内核中使用链表如下所示:
struct my_cool_list{
struct list_head list; /* kernel's list structure */
int my_cool_data;
};
是的,这是可能的
您的建议是,在大多数平台上的大多数编译器中,您可能都不会受到影响,但首先没有一个好的理由这么做,也有很多好的理由不这么做。当然。您可以使用
void*
而不是struct list*
作为nxt
成员。例如:
struct list {
int data;
void *nxt;
};
或者,如果您准备构建一个保证列表的节点将被存储到一个数组中(这对于缓存位置和插入速度来说是非常好的),那么您可以使用大小\u t
struct list {
int data;
size_t nxt;
};
如果您的实现提供了uintpttr\t
(来自
),则可以将这两种类型合并为一种:
struct list {
int data;
uintptr_t nxt;
};
另一种方法是使用并行数组作为“堆”1,一个数组包含数据(无论是标量还是结构),另一个数组存储列表中下一个“节点”的索引,如:
int data[N];
int next[N];
您需要两个“指针”——一个指向列表中的第一个元素,另一个指向“堆”中第一个可用的“节点”
将“next”数组中的所有元素初始化为“指向”下一个元素,但最后一个指向“null”的元素除外:
这种方法的优点:
静态
,这意味着您的二进制文件可能占用了大量内存李>
-1
用作“null”的约定意味着您必须为索引使用有符号类型,这会减少给定数组类型的可用元素数李>
您当然可以使用0
作为“null”,并从1
中计算所有索引;这允许您在索引中使用无符号类型,如size\t
,这意味着您可以使数组尽可能大。只是0
是一个有效的数组索引,而-1
(通常)不是,这就是我在本例中选择它的原因
1.欢迎来到我的数据结构课程,约1987年,该课程使用Fortran 77进行教学。并行数组几乎可以解决所有问题(列表、树、队列等)。
nxt
必须指向列表元素,而不是int
。没有可移植的方法使int*nxt
声明工作。有很多方法可以做到这一点,但它们都是黑客行为,会限制代码的可移植性、可读性和可靠性,而没有任何好处。这样做有什么意义?也许如果你解释了你真正想要达到的目标,那么某人可能会有一个好的建议。我认为关键部分是,没有自我参照结构的帮助。可能,通过int*nxt
OP的意思是*nxt代码>@chatraed我知道OP想要什么。问题不是“什么”,而是“为什么”。@chatraed这是一个理由,也很公平。但这种情况下的原因应该来自OP,而不是其他人。重点是试图理解OP想要实现什么,以便给出一个好的答案。你给出的原因可能是,也可能不是OP的意图。但列表头不是一个自我参照结构吗?您所做的只是在头文件中隐藏循环。@rici:struct list\u head
与struct my\u cool\u list
完全无关。我不明白,连接在哪里。自我指涉意味着它指的是它自己。看起来,结构列表头包含一个指向结构列表头的成员指针,使其具有自引用性。@rici:是的,显然各种结构列表头
是相互关联的。然而,保存有用数据的结构与其成员之间失去了循环性和自引用性。从技术上讲,这不是自引用的,因此这是对这个问题的恰当回答+1,以抵消愚蠢的-1,它似乎没有任何理由。如果您将OP锁定为单一形式的存储持续时间,我不确定我是否同意“无动态内存管理”是一种优势。@undefinedbehaviour:这个示例是故意简化的。显然,您可以动态分配数组,甚至根据需要扩展它们(只需调整空闲列表以适应新元素)。但您不需要管理单个节点的内存。如果你知道你的列表会很小(大约几千字节),为什么还要用动态内存呢?为什么要把列表的节点存储在数组中,因为每个列表节点都知道它的邻居呢?除了更好的缓存位置,你可以通过分配(或以其他方式声明)一次有多个节点。需要指向nxt
项的指针,以便在不移动每个项的情况下重新排列列表。是否有一个开源软件将其付诸实践?我不知道有什么现成的,但我确信有……毕竟,这是我从一本算法书中学到的一个概念。
int head;
int free;
for ( int i = 1; i < N-1; i++ )
next[i-1] = i;
next[N-1] = -1;
free = 0; // first available "node" in the heap
head = -1; // list is empty, head is "null"
if ( free != -1 )
{
int idx = free; // get next available "node" index;
free = next[free]; // update the free pointer
data[idx] = newValue;
next[idx] = -1;
if ( head == -1 )
{
head = idx;
}
else if ( data[idx] < data[head] )
{
next[idx] = head;
head = idx;
}
else
{
int cur = head;
while ( next[cur] != -1 && data[idx] >= data[next[cur]] )
cur = next[cur];
next[idx] = next[cur];
next[cur] = idx;
}
}
int cur = head;
while ( next[cur] != idx && next[cur] != -1 )
cur = next[cur];
if ( next[cur] == idx )
{
next[cur] = next[idx]; // point to the element following idx
next[idx] = free; // add idx to the head of the free list
free = idx;
}