<c:if test="${parameter.label == '<year of case>'}" >
对我来说,令人困惑的部分是当您取消引用双指针typedef struct node node;
struct node {
int data;
node *next;
};
int insert_asc(node **phead, int data) {
node **traser;
node *newnode = malloc(sizeof(node));
if (newnode == 0)
return 0;
newnode->data = data;
for (traser = phead; *traser != 0; traser = &(*traser)->next)
if (data <= (*traser)->data)
break;
newnode->next = *traser;
*traser = newnode;
return 1;
}
时。
traser
为何持有下一个节点的地址?
(*traser)->next
到底是什么?
答案 0 :(得分:0)
您在这里使用双指针来跟踪列表的开头。
如果您在此处使用简单的指针交换了节点,则可能会失去列表中某些节点的地址。
这是因为,如果您要传递一个简单的指针指向列表的开头,那么您将在函数中操作标题地址的副本,因此,当您在函数中交换位置时,标题地址仍然会同样,如果将头替换为另一个节点,则在函数修改列表后,旧头之前的所有节点的地址都会丢失。
编辑:pythontutor.com是一个工具,由于其出色的可视化工具,它可以帮助我非常轻松地了解链表的行为,我强烈建议您使用它。
答案 1 :(得分:0)
在发布的代码中将双指针用于两个单独的目的:
node **phead
:列表的开头通过引用传递,因此如果必须在列表的开头插入新节点,则insert_asc
可以对其进行更新。在C中不可能通过引用传递,实现它的惯用方式是将指针传递给要由函数更新的值,因此传递双指针phead
。
node **traser
:为避免对空列表和插入列表的开头进行特殊处理,程序员使用指针来跟踪插入新节点的位置。 traser
首先指向列表的开头,在这种情况下为phead
的值,并且在指向节点之间的链接时进行更新,即当前节点的next
成员。确定必须在当前节点之后插入新节点。这是无需特殊情况即可实现插入的一种优雅方式。 C允许使用指针,这在Java或javascript中都是不可能的,因为这些语言没有通用的指针。
但是请注意,在比较指针时,可以使用NULL
而不是0
来使代码更具可读性:
typedef struct node node;
struct node {
int data;
node *next;
};
int insert_asc(node **phead, int data) {
node **traser;
node *newnode = malloc(sizeof(node));
if (newnode == NULL)
return 0;
newnode->data = data;
for (traser = phead; *traser != NULL; traser = &(*traser)->next) {
if (data <= (*traser)->data)
break;
}
newnode->next = *traser;
*traser = newnode;
return 1;
}
还要注意,将具有给定值data
的新节点插入具有相同data
值的节点之前。在这种情况下,这没有什么区别,对于具有许多重复项的列表而言,可能会更快一些,但是如果有效负载更加复杂,则此插入方法将实现非稳定排序,而使用<
而不是{ {1}}可使排序稳定。
为说明起见,这是替代实现,该实现不使用双指针作为插入点,并且在特殊情况下需要额外的测试:
<=