我是学生(还是新秀),我有问题。我必须删除单链列表中的一对节点,其总和等于 k 。 例如,如果链接列表为 13-> 4-> 5-> 4-> 3 和 k = 9 ,则我的函数应将列表转换为 13-> 3 (4 + 5 = 9,5 + 4 = 9)。这是我未完成的代码:
typedef struct _node
{
int value;
struct _node* next;
}Node;
void remove(Node **list, int k)
{
if(*list == NULL || (*list)->next == NULL)
return;
Node *prev = *list;
Node *tmp = (*list)->next;
while(tmp != NULL)
{
if(prev->value + tmp->value == k)
{
free(prev);
prev = tmp->next;
free(tmp);
tmp = tmp->next->next;
}
}
}
我有一个主意,但是我不知道如何在while循环中设置条件。 有人知道如何重写吗?
答案 0 :(得分:1)
现在,您在第一个匹配项处断开链接:在您的示例中,删除4后,13的next
仍指向该链接,并且一个悬空指针也是如此。但这不会发生,因为您永远不会从13移动到任何地方,因为您只会在删除一个元素时才向前迭代(这对13-> 4不会发生)。
您应该考虑的第三件事是,您应该实际标记要删除的元素,否则您将无法删除示例中的后四个元素。
答案 1 :(得分:0)
首先->您未在列表中前进,因此将导致无限循环。
第二个->如果tmp
的下一个节点是NULL
,则tmp=tmp->next->next
会给您分段错误。
第三步->释放内存时,您也在中断链表,因此在基础代码中声明了pointToPrev
指针,该指针指向prev
后的节点指针,但在释放内存的情况下,它将指向网络节点tmp
来保存列表。
更好地将while循环更改为此:
` int indicator=0;
Node *pointToPrev = *list;
if(prev->value + tmp->value == k)
{
*list=temp->next;
free(tmp);
free(prev);
indicator=2;
}
while((tmp != NULL)&&(indicator!=2))
{
if(prev->value + tmp->value == k)
{
free(prev);
pointToPrev->next = tmp->next;
free(tmp)
break; //AS YOU DON'T NEED TO COMPLETE THE ENTIRE WHILE LOOP AS SUM HAS BEEN ALREADY FOUND
}
else //THIS WILL SAVE YOU FROM THE INFINITE LOOP
{
tmp = tmp->next;
prev = prev->next;
if(indicator==0)
{
pointToPrev = *list;
indicator=1;
}
else
pointToPrev=pointToPrev->next;
}
}
答案 2 :(得分:0)
以下事实使这个问题变得复杂:您有两个重叠的条件来控制是否应删除给定节点:如果其值与上一个节点的值之和是目标值,或者如果它与 next 节点的值之和是目标值。而且,除了当它是最后一个节点之外,您始终将下一个节点与下一个节点进行比较,因此,您必须纪念它所携带的值,否则必须避免删除它。
可以通过从第二个节点开始的普通链表遍历来解决此问题(或者,如果少于两个节点,则无需执行任何操作)。每次迭代
循环终止后,请删除最后一个节点(如果适用)。您需要在每次迭代之间携带足够的状态,以适当地执行删除操作,并记住上一次迭代中求和评估的结果,但是总的来说,这并不比按值删除单个节点困难得多。
这种方法非常简单,因为它将每次评估中必须考虑的案例数限制为两个,它永远不需要在列表中比下一个节点更进一步向前看,并且当删除一个节点时,该节点就是始终与当前节点具有相同的关系。该代码应保留为应做的练习。