这是我的代码,至少是重要的部分。每当我运行它并试图删除head
节点时,它都不会起作用(输出将是一个大负数(。它将适用于所有其他节点。
是我的代码有问题,还是你不能替换head
?
node* displayList(node* head) {
node* curr = head;
while (curr != NULL) {
cout << curr->data << " ";
curr = curr->next;
}
return NULL;
}
node* deleteVal(node* head, int val) {
node* cur, * prev;
if (head == NULL)
return head;
if (head->data == val) {
cur = head->next;
delete head;
head = cur;
return head;
}
cur = head;
prev = NULL;
while (cur->data != val && cur != NULL) {
prev = cur;
cur = cur->next;
}
if (cur == NULL) {
return head;
}
prev->next = cur->next;
return head;
}
int main() {
node* head1 = initNode(), * head2=initNode(), * head3 = initNode();
int val;
head1 = input();
head2 = input();
head3 = input();
conca(head1, head2, head3);
cout << "the concatated list is: ";
displayList(head1);
cout << endl<<"enter the value you want to delete: ";
cin >> val;
deleteVal(head1, val);
cout << "the new list is: ";
displayList(head1);
return 0;
}
对于启动器,while循环的条件
while (cur->data != val && cur != NULL) {
prev = cur;
cur = cur->next;
}
必须像一样更改
while ( cur != nullptr && cur->data != val) {
prev = cur;
cur = cur->next;
}
此外,您确实需要删除找到的节点,如
prev->next = cur->next;
delete cur;
return head;
而且在主要情况下,你必须将指针重新分配给像这样的头节点
head1 = deleteVal(head1, val);
有了显示的更新,功能可以按照以下方式
node* deleteVal(node* head, int val) {
node* cur, * prev;
if (head == NULL)
return head;
if (head->data == val) {
cur = head->next;
delete head;
head = cur;
return head;
}
cur = head;
prev = NULL;
while ( cur != NULL && cur->data != val ) {
prev = cur;
cur = cur->next;
}
if (cur == NULL) {
return head;
}
prev->next = cur->next;
delete cur;
return head;
}
并且在主写入
head1 = deleteVal(head1, val);
deleteVal()
编码错误。
当NOT删除head
节点时,如果在列表中找不到val
,则while
循环将显示未定义的行为。在这种情况下,在检查最后一个节点后,cur
将变为NULL
,然后循环将尝试再次访问cur->data
,即UB。
您需要交换while
语句的条件,以便在访问其data
成员之前检查cur
的NULL
:
while (cur != NULL && cur->data != val)
此外,如果while
循环在其余节点中确实找到了val
,则只需将找到的节点从列表中取消链接,但实际上并没有对该节点进行delete
'链接,因此会泄漏其内存。
试试这个:
node* deleteVal(node* head, int val) {
node *cur, *prev;
if (head == NULL)
return head;
if (head->data == val) {
cur = head->next;
delete head;
return cur;
}
// we know the head node doesn't match, no need to
// test it again, so start the loop on the 2nd node...
cur = head->next;
prev = head;
while (cur != NULL && cur->data != val) {
prev = cur;
cur = cur->next;
}
if (cur != NULL) {
prev->next = cur->next;
delete cur;
}
return head;
}
话虽如此,所显示的代码还有其他问题。
CCD_ 17忽略了CCD_ 18的返回值。因此,如果head1
所指向的节点实际上已从列表中删除,则main()
无法知道这一点,从而最终将现在无效的node*
指针传递给displayList()
。因此,您需要将deleteVal()
的返回值分配回head1
,以反映新的列表状态:
head1 = deleteVal(head1, val);
这就是为什么按返回值返回新列表指针不是一个好的设计选择(除非在C++17及更高版本中将其标记为nodiscard
(,因为它太容易被忽略。更好的设计选择是通过引用/指针传入调用方的变量,这样函数就可以在需要时直接更新调用方的参数。
此外,当调用input()
时,main()
正在泄漏head1
、head2
和head3
节点。您正在使用initNode()
创建新节点,然后重新分配指针以指向由input()
创建的新节点,因此您将无法访问initNode()
中的原始节点。
事实上,即使在调用deleteVal()
之后,在退出程序之前也不会释放任何剩余的节点。虽然操作系统确实会在程序退出时回收所有使用过的内存,但最好明确释放您分配的任何内存。
此外,您的deleteVal()
是不必要的复杂,它可以大大简化。
此外,displayList()
根本没有充分的理由返回任何内容。
话虽如此,不如试试这样的东西:
void displayList(node* head) {
node* curr = head;
while (curr != NULL) {
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
void deleteVal(node* &head, int val) {
node *cur = head, **prev = &head;
while (cur != NULL) {
if (cur->data == val) {
*prev = cur->next;
delete cur;
return;
}
prev = &(cur->next);
cur = cur->next;
}
}
void deleteList(node* &head) {
node *cur = head, *next;
head = NULL;
while (cur != NULL) {
next = cur->next;
delete cur;
cur = next;
}
}
int input() { // <-- return int, not node* !
...
return ...; // <-- just the user's entered value, not a node wrapping the value
}
int main() {
node* head1 = initNode(), *head2 = initNode(), *head3 = initNode();
head1->data = input();
head2->data = input();
head3->data = input();
conca(head1, head2, head3);
cout << "the concatenated list is: ";
displayList(head1);
cout << "enter the value you want to delete: ";
int val;
cin >> val;
deleteVal(head1, val);
cout << "the new list is: ";
displayList(head1);
deleteList(head1);
return 0;
}