为什么我无法在链表中输入元素,而函数正在运行?
Why am I unable to enter elements in the linked list while the function is working otherwise?
我写了一个程序将两个排序的链表合并为一个,这个函数是我用来做的,但它不起作用。该函数的代码如下:
void combine(Node **temp, Node *temp_1, Node *temp_2){
while(temp_1 != NULL || temp_2 != NULL){
if(temp_1->data > temp_2->data){
push(temp, temp_2->data);
temp_2 = temp_2->next;
}
else{
push(temp, temp_1->data);
temp_1 = temp_1->next;
}
}
while(temp_1 != NULL){
push(temp, temp_1->data);
temp_1 = temp_1->next;
}
while(temp_2 != NULL){
push(temp, temp_2->data);
temp_2 = temp_2->next;
}
}
现在,此代码不会向最终链表添加任何内容。如果我写类似
push(temp, temp_1->data);
它会很好地添加元素,所以问题肯定不在于推送功能。有人能告诉我上面的代码有什么问题吗?
完整代码如下URL:
https://ide.geeksforgeeks.org/FZ8IS4PADE
问题是 while
条件:
while(temp_1 != NULL || temp_2 != NULL){
这将允许在这两个指针中只有 一个 为空时执行循环体,这将导致循环体中第一条语句出现未定义的行为:
if(temp_1->data > temp_2->data){
||
应该是 &&
。这将解决您的问题。
关于您的代码的其他说明
不要使用 NULL
来比较你的指针变量,但是 nullptr
使用 push
会使您的代码效率低下:在每次推送时,您的代码都会开始遍历整个列表以找到它的结尾。由于您实际上知道最后一个节点是什么(因为它是在循环的前一次迭代中创建的),这是在浪费时间。相反,保留对正在创建的列表的 tail 的引用。由于在 combine
进程开始时没有尾部,因此创建一个位于将返回的真实列表之前的“哨兵”节点可能很有用。
使用更好的变量名。 temp
根本不是临时的。是调用者想要得到的结果:这个名字有误导性。
避免代码重复。除了从中复制的列表外,最后两个循环是相同的,并且此代码再次类似于主循环中的部分。因此,创建一个函数来执行将节点从源列表复制到另一个列表末尾的工作,并使两个指针都前进。
这是它的样子:
void copyNode(Node **source, Node **targetTail) {
*targetTail = (*targetTail)->next = new Node((*source)->data);
*source = (*source)->next;
}
void combine(Node **result, Node *head_1, Node *head_2){
Node *sentinel = new Node(0); // Dummy
Node *current = sentinel;
while(head_1 != nullptr && head_2 != nullptr){
if(head_1->data > head_2->data){
copyNode(&head_2, ¤t);
}
else{
copyNode(&head_1, ¤t);
}
}
if (head_1 == nullptr) {
head_1 = head_2;
}
while (head_1 != NULL) {
copyNode(&head_1, ¤t);
}
*result = sentinel->next;
delete sentinel;
}
我写了一个程序将两个排序的链表合并为一个,这个函数是我用来做的,但它不起作用。该函数的代码如下:
void combine(Node **temp, Node *temp_1, Node *temp_2){
while(temp_1 != NULL || temp_2 != NULL){
if(temp_1->data > temp_2->data){
push(temp, temp_2->data);
temp_2 = temp_2->next;
}
else{
push(temp, temp_1->data);
temp_1 = temp_1->next;
}
}
while(temp_1 != NULL){
push(temp, temp_1->data);
temp_1 = temp_1->next;
}
while(temp_2 != NULL){
push(temp, temp_2->data);
temp_2 = temp_2->next;
}
}
现在,此代码不会向最终链表添加任何内容。如果我写类似
push(temp, temp_1->data);
它会很好地添加元素,所以问题肯定不在于推送功能。有人能告诉我上面的代码有什么问题吗?
完整代码如下URL: https://ide.geeksforgeeks.org/FZ8IS4PADE
问题是 while
条件:
while(temp_1 != NULL || temp_2 != NULL){
这将允许在这两个指针中只有 一个 为空时执行循环体,这将导致循环体中第一条语句出现未定义的行为:
if(temp_1->data > temp_2->data){
||
应该是 &&
。这将解决您的问题。
关于您的代码的其他说明
不要使用
NULL
来比较你的指针变量,但是nullptr
使用
push
会使您的代码效率低下:在每次推送时,您的代码都会开始遍历整个列表以找到它的结尾。由于您实际上知道最后一个节点是什么(因为它是在循环的前一次迭代中创建的),这是在浪费时间。相反,保留对正在创建的列表的 tail 的引用。由于在combine
进程开始时没有尾部,因此创建一个位于将返回的真实列表之前的“哨兵”节点可能很有用。使用更好的变量名。
temp
根本不是临时的。是调用者想要得到的结果:这个名字有误导性。避免代码重复。除了从中复制的列表外,最后两个循环是相同的,并且此代码再次类似于主循环中的部分。因此,创建一个函数来执行将节点从源列表复制到另一个列表末尾的工作,并使两个指针都前进。
这是它的样子:
void copyNode(Node **source, Node **targetTail) {
*targetTail = (*targetTail)->next = new Node((*source)->data);
*source = (*source)->next;
}
void combine(Node **result, Node *head_1, Node *head_2){
Node *sentinel = new Node(0); // Dummy
Node *current = sentinel;
while(head_1 != nullptr && head_2 != nullptr){
if(head_1->data > head_2->data){
copyNode(&head_2, ¤t);
}
else{
copyNode(&head_1, ¤t);
}
}
if (head_1 == nullptr) {
head_1 = head_2;
}
while (head_1 != NULL) {
copyNode(&head_1, ¤t);
}
*result = sentinel->next;
delete sentinel;
}