Visual Studio 2008 C
我对这个链接列表无法理解的是在if语句的else部分添加尾部。
当头部和尾部被分配时,node_temp的尾部和头部的内存地址都指向相同的内存位置。
但是,在else部分中,头部实际上仍然指向尾部。有些东西我无法解释,也不了解其他部分?
我希望有人可以更好地为我解释。
static struct convert_temp
{
size_t cel;
size_t fah;
struct convert_temp *next;
} *head = NULL, *tail = NULL;
/** Add the new converted temperatures on the list */
void add(size_t cel, size_t fah)
{
struct convert_temp *node_temp = NULL; /* contain temp data */
node_temp = malloc(sizeof(*node_temp));
if(node_temp == NULL)
{
fprintf(stderr, "Cannot allocate memory [ %s ] : [ %d ]\n",
__FUNCTION__, __LINE__);
exit(0);
}
/* Assign data */
node_temp->cel = cel;
node_temp->fah = fah;
node_temp->next = NULL;
if(head == NULL)
{
/* The list is at the beginning */
head = node_temp; /* Head is the first node = same node */
tail = node_temp; /* Tail is also the last node = same node */
}
else
{
/* Append to the tail */
tail->next = node_temp;
/* Point the tail at the end */
tail = node_temp;
}
}
答案 0 :(得分:27)
第一次将一个元素(我们称之为A
)添加到列表中时,head
为空,您将浏览if
部分。这意味着在添加第一个元素时,head
和tail都设置为指向A
。
现在让我们添加另一个元素B
。这一次,head
不为空,因此它会通过else
部分,将tail
设置为B
,但head
指向A
}。
这是预期的,您现在head
指向A
,A
指向B
,B
指向空(null)和{ {1}}指向tail
。
让我们一步一步来。
B
你可以在每个阶段(除了初始阶段)看到当前尾部被设置为指向新节点(已经指向其下一个节点为NULL),然后尾部指针被更新为指向 new 最后一个节点。
事实上,让我们在 more 细节中逐行添加C(逐行),这样你就可以看到每行代码的作用(我已重命名为Initial state: head -+-> null
|
tail -+
Insert item A: head -+-> A ---> null
|
tail -+
Insert item B: head ---> A -+-> B ---> null
|
tail --------+
Insert item C: head ---> A ---> B -+-> C ---> null
|
tail ---------------+
到node_temp
只是为了帮助格式化):
node
然后最终Starting state: head ---> A -+-> B ---> null
|
tail --------+
node = malloc(sizeof(*node)); node ---> C ----------> ?
(allocate node C) head ---> A -+-> B ---> null
|
tail --------+
node->next = NULL; node ---> C --------+
(ignore payload cel/fah |
for now since it's not head ---> A -+-> B -+-> null
relevant to the list |
structure) tail --------+
tail->next = node; node ---------------+
(first in else clause) |
head ---> A -+-> B -+-> C ---> null
|
tail --------+
tail = node; node ---------------+
(second in else clause) |
head ---> A ---> B -+-> C ---> null
|
tail ---------------+
消失,因为它是一个局部变量并且你有最终状态:
node
在单链表中维护 head ---> A ---> B -+-> C ---> NULL
|
tail ---------------+
指针的优点是,当您尝试将项目添加到最后时,必须单步执行整个列表以找到结束。
遍历整个列表会使最后插入tail
次操作(所用时间取决于列表中的项目数)。 O(n)
指针的使用使得tail
时间操作(与列表大小无关的时间相同)。
顺便说一下,双向链表对O(1)
指针有额外的用处 - 它使用tail
和快速开始从列表末尾到开始的遍历。 tail
指针代替prev
和head
指针。
答案 1 :(得分:4)
else-part只更新列表的tail
,因为当你附加到链接列表时头部不会改变。
保持指向缓冲区尾部元素的指针是一种优化,因此您不必在每个附加项的头部逐步完成整个列表。
答案 2 :(得分:1)
头部仍然指向尾巴。 Head指向前尾部。当列表只包含一个元素时,它既是头部也是尾部。附加新节点后,尾指针已更新。头指针仍然指向第一个节点,这是正确的。
答案 3 :(得分:1)
在第一次调用add时,head和tail将指向新创建的内存块。所有后续的add调用都将通过else部分进行调整,这只会改变尾部指针,基本上修改旧的tail->然后指向新的内存块,然后更新tail也指向这个新的内存块。
这是一种有效的追加方式。如果只使用了head,那么每次添加一个新的node_temp时,你必须从头开始遍历所有下一个指针,直到你到达之前添加的node_temp(其下一个指针为NULL),然后添加新节点。这将是O(n)算法,而不是上面的O(1)。