我正在尝试实现一个从链表中删除节点的函数。到目前为止,我只能删除列表的第一个节点(3)。
我试着从delete转到for循环,我认为内存分配不好,我已经挣扎了几天,我不明白,请帮我一点忙,这是我在大学里收到的话题。
#include <stdio.h>
#include <stdlib.h>
typedef struct nod
{
int key;
struct nod *urm;
} NOD;
NOD *first=0,*last=0;
void add(int x)
{
NOD *p=(NOD*)malloc(sizeof(NOD));
p->key=x;
p->urm=0;
if(0==first)
{
first=p;
last=p;
}
else{
last->urm=p;
last=p;
}
}
void delete(int x)
{
NOD *q,*p;
if(first->key==x)
{
p=first;
first=first->urm;
free(p);
}
else{
for(p=q=first;p=0;q=p,p=p->urm)
{
if(p->key==x)
{
q->urm=p->urm;
if(p==last)
{
last=q;
}
free(p);
}
}
}
}
void show()
{
for(NOD *p=first;p!=0;p=p->urm)
{
printf("%d ",p->key);
}
printf("\n");
}
int main()
{
add(3);
add(1);
add(2);
add(5);
show();
delete(2);
show();
return 0;
}发布于 2020-04-28 04:59:52
对于初学者来说,您显示的代码不是C++代码。这是一个C代码。
当函数依赖于全局变量时,定义像first和last这样的全局变量并不是一个好主意。在这种情况下,您不能在一个程序中创建多个列表。
至于函数delete,一般来说,它具有未定义的行为。可以为空列表调用它。
此外,在这个循环中
for(p=q=first;p=0;q=p,p=p->urm)条件表达式中有一个拼写错误。您正在使用赋值运算符,而不是比较运算符。
当列表只包含一个节点时,函数忽略大小写,因为在这种情况下,它不会更新最后一个节点。
不过,使用您的方法时,函数delete可能如下所示。
void delete(int x)
{
if ( first )
{
if ( first->key == x )
{
NOD *tmp = first;
first = first->urm;
free( tmp );
if ( first == NULL ) last = NULL;
}
else
{
NOD *p = first;
while ( p->urm != NULL && p->urm->key != x )
{
p = p->urm;
}
if ( p->urm != NULL )
{
NOD *tmp = p->urm;
p->urm = p->urm->urm;
free( tmp );
if ( p->urm == NULL ) last = p;
}
}
}
} 这是一个演示程序。
#include <stdio.h>
#include <stdlib.h>
typedef struct nod
{
int key;
struct nod *urm;
} NOD;
NOD *first=0,*last=0;
void add(int x)
{
NOD *p=(NOD*)malloc(sizeof(NOD));
p->key=x;
p->urm=0;
if(0==first)
{
first=p;
last=p;
}
else{
last->urm=p;
last=p;
}
}
void delete(int x)
{
if ( first )
{
if ( first->key == x )
{
NOD *tmp = first;
first = first->urm;
free( tmp );
if ( first == NULL ) last = NULL;
}
else
{
NOD *p = first;
while ( p->urm != NULL && p->urm->key != x )
{
p = p->urm;
}
if ( p->urm != NULL )
{
NOD *tmp = p->urm;
p->urm = p->urm->urm;
free( tmp );
if ( p->urm == NULL ) last = p;
}
}
}
}
void show()
{
for(NOD *p=first;p!=0;p=p->urm)
{
printf("%d ",p->key);
}
printf("\n");
}
int main()
{
add(10);
add(20);
add(30);
add(40);
show();
delete(30);
show();
add( 50 );
add( 60 );
add( 70 );
add( 80 );
show();
delete(80);
show();
return 0;
}它的输出是
10 20 30 40
10 20 40
10 20 40 50 60 70 80
10 20 40 50 60 70 发布于 2020-04-28 06:43:14
通过同时使用指向NOD的指针和指向NOD的指针遍历列表,可以大大简化从列表中删除节点的过程。这允许您将当前地址处的节点设置为node->urm,而无需跟踪列表中的前一个节点,例如
/** delete node with key v from list (for loop) */
void delete (int v)
{
NOD **ppn = &first; /* pointer to pointer to first*/
NOD *pn = first; /* pointer to first */
for (; pn; ppn = &pn->urm, pn = pn->urm) {
if (pn->key == v) {
*ppn = pn->urm; /* set node at address to next node */
free (pn); /* free deleted node */
break;
}
}
}有关除指向节点的指针之外还使用节点地址的优点的进一步讨论,请参阅Linus on Understanding Pointers。
发布于 2020-04-28 05:09:26
我认为您的for循环条件在delete函数中是不正确的:
for(q=first, p=first->urm; p!=0; q=p, p=p->urm)只要改变条件,它就应该可以工作了。
https://stackoverflow.com/questions/61468120
复制相似问题