#define SWAP_PTRS(a, b) do { void *t = (a); (a) = (b); (b) = t; } while (0)
Node* MergeLists(Node* list1, Node* list2)
{
Node *list = NULL, **pnext = &list;
if (list2 == NULL)
return list1;
while (list1 != NULL)
{
if (list1->data > list2->data)
SWAP_PTRS(list1, list2);
*pnext = list1;
pnext = &list1->next;
list1 = *pnext;
}
*pnext = list2;
return list;
}
此代码来自此处,this question的所选答案。
我在这里无法理解3行:
*pnext = list1;
pnext = &list1->next;
list1 = *pnext;
有人可以帮助我吗?为我解释一下?
编辑:我可以更改这两行:
pnext = &list1->next;
list1 = *pnext;
到
list = list-> next;
答案 0 :(得分:3)
从一开始:您将返回两个列表和一个新的列表头。 pnext最初指向那个。
代码旨在尽可能少地执行指针重新分配,因此尝试保持输入列表的初始“下一个”指针保持不变。
list1 pnext->list->Null
|
V
o->o->o...
list2
|
V
o->o->o...
交换是为了确保较小的元素是list1的第一个元素。这些行的作用是:
一步一步走:
*pnext = list1;
获取* pnext(在第一次迭代之前是列表)以指向包含最小元素的节点:
list1
|
V
o->o->o...
^
|
list<-pnext
list2
|
V
o->o->o...
pnext = &list1->next;
这是棘手的部分,如前所述&amp;运算符的优先级较低。它也很难以图形方式显示,因为它实际上是在查看Node构造的一部分。虽然如此:
list1
|
V
o---->o->o...
^ ^
| |
list x<-pnext
list2
|
V
o->o->o...
其中x是list1指向的o的下一个指针。
list1 = *pnext;
在处理第一个元素时推进list1 head。
list1<-pnext
|
V
o->o->o->...
^
|
list
list2
|
V
o->o->o->...
您与此处的列表无关,因为您希望将其作为合并列表的头部返回。
不变量有pnext指向最后处理的元素的下一个指向的位置,这是list1-2中最小的元素应该去的地方。有趣的事情发生在交换中,尝试自己计算出确切的程序(很难像这样绘制,并且很好地练习以了解**的作用)。如果我找到一个很好的方法来绘制它,我可能会添加它。
您不能使用list = list-> next;
,因为它会执行以下操作:
list1
|
V
o->o->o->...
^
|
list
list2
|
V
o->o->o->...
这意味着你会失去那种孤独的o(以及随着循环的进展而最终的一切)。
编辑:最后的*pnext = list2;
执行此操作:
循环终止(上述陈述之前的状态):
list1<-pnext
|
V
o->o->o->null
^
|
list
o->o->o->...
^
|
list2
声明后:
list1
|
V
o->o->o Null
^ |
| |
list |
V
o->o->o->...
^
|
list2<-pnext
该语句将剩余列表附加到列表的末尾。然后返回Node * list,指向合并列表的头部。
EDIT2:
一直以来,pnext会更好地代表:
list1
|
V
o->o->o Null
^ |
| |<-pnext
list |
V
o->o->o->...
^
|
list2
这意味着它指向最后处理的节点的下一个指针。
答案 1 :(得分:2)
pnext
是指向Node
指针的指针。
“*pnext
”表示您正在使用pnext
指向的值。因此:
*pnext = list1;
表示指向pnext
的任何指针现在指向与list1
相同的东西。
为清楚起见,下一行应放在括号内:
pnext = &(list1->next);
list1->next
表示您正在访问next
所指向的list1
属性,&
表示获取该元素的地址。本质上意味着你使pnext
指向指向下一个元素的指针。
最后一行:
list1 = *pnext;
表示您获取pnext
指向的值并将其分配给list1
。
答案 2 :(得分:1)
list1
的类型为Node*
,pnext
的类型为Node**
,这意味着它应该包含类型为Node*
的变量的地址。
*pnext = list1;
取消引用pnext
后,您会获得Node*
。所以,这个任务是正确的。
pnext = &list1->next;
此处->
的优先级高于&
。因此,它返回指针的地址(即Node *类型的地址)
list1 = *pnext;
这与第一个陈述正好相反。取消引用pnext
会将Node*
提供给list1
。
是的,你可以改变它(即,逻辑上他们做同样的事情) -
pnext = &list1->next;
list1 = *pnext;
到
list1 = list1->next ;
但是,你有一个声明 -
*pnext = list2;
如果pnext
未按两步序列初始化,则取消引用未初始化的指针(即*pnext
)将导致分段错误。这就是原因。
答案 3 :(得分:0)
尝试安装visual studio express edition。 在VS-2012中调试程序后,只需将鼠标悬停在指针上,它就会通过解除引用地址来显示内容。