C++ 递归函数,用于删除链表中字符的所有实例
我编写了一个递归函数来删除具有特定数据值的节点,但是它不能正常工作C++ 递归函数,用于删除链表中字符的所有实例,c++,linked-list,nodes,C++,Linked List,Nodes,我编写了一个递归函数来删除具有特定数据值的节点,但是它不能正常工作 Node * removeAll(Node *top, char c){ if(top == NULL) return NULL; Node *newTop; if(top->data == c){ newTop = top->next; delete top; }else{ newTop = top; }
Node * removeAll(Node *top, char c){
if(top == NULL)
return NULL;
Node *newTop;
if(top->data == c){
newTop = top->next;
delete top;
}else{
newTop = top;
}
newTop->next = removeAll(newTop->next,c);
return newTop;
}
提供给函数的链表包含值HE l o
我希望输出的列表包含值HE o
,但它却包含值HE l o
更改此项:
if(top->data == c){
newTop = top->next;
delete top;
}else{
newTop = top;
}
为此:
while(top && top->data == c){
newTop = top->next;
delete top;
top = newTop;
}
newTop = top;
这样,在移动到下一个元素之前,包含目标值的连续元素都将被删除
另一方面,如果以迭代方式而不是递归方式编写此函数,它可能会占用更少的内存,速度更快。我将以教程的形式回答此问题,因为几乎每个人在学习如何递归思考时都会遇到一些困难 请注意,因为它使用
while
循环,@Edward的答案不是完全递归的形式
当你学习时,首先用人类语言写出答案的递归描述总是有帮助的。从代码开始将注意力从思考算法转移到不重要的细节上,如语法和指针语义。用英语
删除字符C的形式[HEAD,rest\u of_list]
的列表等于删除字符C且HEAD
可选地挂起的形式rest\u of_list
。是否预加HEAD
取决于它是否等于C
这里的HEAD
是一个字符,而rest\u of_list
本身就是一个列表
递归部分正在从列表的剩余部分删除C
。请注意,递归发生在比输入短一个字符的字符串上。太好了!这意味着算法在从一个递归调用到下一个递归调用之间取得了进展
我们还需要描述一个递归停止的“基本情况”。在这里,由于列表从一个调用到下一个调用越来越短,因此尝试使用空列表是合乎逻辑的。用英语
当输入列表为空时,它不能包含C
,因此返回空列表
我们已经准备好编写代码了。首先是基本情况。您的实现很好。在通常的C列表实现中,NULL
指针是空列表
Node *removeAll(Node *list, char c) {
// Base case.
if (list == NULL) return NULL;
// Recursive case.
// TODO: Complete me.
}
对于递归的情况,HEAD
正如我们用英语写的那样,是C中的list->data
,而rest\u是list->next
。因此,请继续写下:
// Recursive case.
char head = list->data;
Node *rest = list->next;
递归案例本身有两个案例。如果head
是c
,那么我们只需返回rest
,并删除c
if (c == head) return removeAll(rest, c);
剩下的情况是,head
不等于c
。这里有一个选择。您需要一个节点来容纳c
。您可以重新使用当前保存它的列表,这意味着您正在更改原始列表。或者您可以分配一个新节点,这意味着原始列表保持不变。在实际应用中,此决策可能非常重要。假设您希望保持原始列表的完整性。预编是用
return allocateNewNode(head, removeAll(rest, c));
此处allocateNewNode
获取未用于其他列表的节点的新内存。例如,它可以调用malloc
另一方面,如果要更改输入列表(术语mutate
非常常见),请修改列表中的第一个节点
list->next = removeAll(rest, c);
return list;
总的来说,突变的情况是:
Node *removeAll(Node *list, char c) {
// Base case: on empty list, return empty list.
if (list == NULL) return NULL;
// Recursive cases. Extract head value and rest of list.
char head = list->data;
Node *rest = list->next;
// If head is C, return rest with C removed.
if (c == head) return removeAll(rest, c);
// Otherwise prepend C to rest with C removed by mutating the first list node,
// which already contains head.
list->next = removeAll(rest, c);
return list;
}
我希望这对您和其他试图掌握递归思想的人有所帮助。似乎是使用调试程序的好机会。当简单的迭代循环就足够时,为什么要使用递归?这也可以避免在大列表中循环时出现堆栈溢出的风险。`newTop=top->next“应该是“top=top->next”,但如果不是这样,我感谢您的帮助