C语言。有两个链表a和b,从a链表中删去与b链表中有相同学号的那些结点!

#include <stdio.h>
#include <malloc.h>

struct student
{
int num;
char name[10];
struct student *next;

};

void main()
{ void print(struct student *head);
struct student *creat();
struct student *solve(struct student *head_a,struct student *head_b);
struct student *head,*head_a,*head_b;
head_a=creat();
head_b=creat();

head=solve(head_a,head_b);
print(head);

}

struct student *creat()
{
struct student *head,*p,*p1;
p1=(struct student *)malloc(sizeof(struct student));
head=p=p1;
printf("输入学号和姓名0停止接收数据\n");
printf("请输入学生学号和姓名:");
scanf("%d %s",&p->num,&p->name);
while(p->num!=0)
{
printf("请输入学生学号和姓名:");

p1->next=p;
p1=p;
p=(struct student *)malloc(sizeof(struct student));
scanf("%d %s",&p->num,&p->name);

}

p1->next=NULL;
return head;
}

struct student *solve(struct student *head_a,struct student *head_b)
{
struct student *p,*p1,*t;
p=p1=head_a;
t=head_b;
while(p!=NULL)
{
t=head_b;
while(t->next!=NULL&&(t->num!=p->num))
{

t=t->next;

}
if(t->num==p->num)
{
if(p==head_a)
{
head_a=head_a->next;
p1=p=head_a;
}
else
{
p1->next=p->next;
p=p->next;
}

}
else
{
p1=p;
p=p->next;
}

}
return head_a;
}

void print(struct student *head)
{
struct student *p;

while(p!=NULL)
{
printf("%d %s\n",p->num,p->name);
p=p->next;

}

}

帮我看看我哪里写错了。。。。。答的好有追加~

/*
有两个链表a和b,从a链表中删去与b链表中有相同学号的那些结点!
*/
#include <stdio.h>
#include <string.h>
#include <malloc.h>

struct student
{
int num;
char name[10];
struct student *next;
};

int main()
{
void print(struct student *head);
struct student *creat();
struct student *solve(struct student *head_a,struct student *head_b);
struct student *head,*head_a,*head_b;
printf("********初始化链表A********\n");
head_a=creat();
printf("********输出链表A********\n");
print(head_a);

printf("********初始化链表B********\n");
head_b=creat();
printf("********输出链表B********\n");
print(head_b);

printf("********从a链表中删去与b链表中有相同学号的那些结点********\n");
head=solve(head_a,head_b);

print(head);

return 0;
}

struct student *creat()
{
struct student *head,*p,*p1;

/*
【1】
注意 creat 函数中认为链表是有一个表头节点的,也就是链表的第一节点是 head->next,
而不是 head。

而下面的 solve 函数和 print 函数都认为链表是没有表头节点的,也就是他们认为链表的
第一个节点是:head 而不是 head->next 。

这是你程序出错的原因所在。

改正:为了方便,把链表改成不带头节点的,也就是第一个节点为:head
*/
p = p1=(struct student *)malloc(sizeof(struct student));
head = NULL;

printf("请输入学生学号和姓名(输入学号0和姓名0停止接收数据):");
scanf("%d%s",&p->num,&p->name);
while(!(p->num == 0 && strcmp(p->name,"0")==0))
{
if(head == NULL)
{
head = p;
p1=head;
p=(struct student *)malloc(sizeof(struct student));
}
else
{
p1->next=p;
p1=p;
p=(struct student *)malloc(sizeof(struct student));
}

printf("请输入学生学号和姓名(输入学号0和姓名0停止接收数据):");
scanf("%d%s",&p->num,&p->name);
}
p1->next=NULL;
return head;
}

struct student *solve(struct student *head_a,struct student *head_b)
{
struct student *p,*p1,*t;
p=p1=head_a;

if(head_b == NULL)
{
return head_a;
}

while(p!=NULL)
{
t=head_b;
/*
【2】
while(t->next!=NULL && (t->num!=p->num))
这里有个问题:
a)你不能保证 head_b 不是一个空链表,也就可能是 t == NULL 的情况。
这时引用 t->next 会出错 !!!

改正: 在一开始就加上 head_b == NULL 的判断
*/

while(t->next!=NULL && (t->num!=p->num))
{
t=t->next;
}

if(t->num==p->num)
{
if(p==head_a)
{
head_a=head_a->next;
p1=p=head_a;
}
else
{
p1->next=p->next;
p=p->next;
}
}
else
{
p1=p;
p=p->next;
}
}
return head_a;
}

void print(struct student *head)
{
struct student *p;
/*
这个错误太明显了,指针 p 没有赋初值

改正:p = head;
*/
p = head;
while(p!=NULL)
{
printf("%d %s\n",p->num,p->name);
p=p->next;
}
}

/*
测试数据:
1 a
2 b
3 c
4 d
5 e
6 f
7 g
0 0
2 b
5 e
0 0

输出结果:
********初始化链表A********
请输入学生学号和姓名(输入学号0和姓名0停止接收数据):1 a
请输入学生学号和姓名(输入学号0和姓名0停止接收数据):2 b
请输入学生学号和姓名(输入学号0和姓名0停止接收数据):3 c
请输入学生学号和姓名(输入学号0和姓名0停止接收数据):4 d
请输入学生学号和姓名(输入学号0和姓名0停止接收数据):5 e
请输入学生学号和姓名(输入学号0和姓名0停止接收数据):6 f
请输入学生学号和姓名(输入学号0和姓名0停止接收数据):7 g
请输入学生学号和姓名(输入学号0和姓名0停止接收数据):0 0
********输出链表A********
1 a
2 b
3 c
4 d
5 e
6 f
7 g
********初始化链表B********
请输入学生学号和姓名(输入学号0和姓名0停止接收数据):2 b
请输入学生学号和姓名(输入学号0和姓名0停止接收数据):5 e
请输入学生学号和姓名(输入学号0和姓名0停止接收数据):0 0
********输出链表B********
2 b
5 e
********从a链表中删去与b链表中有相同学号的那些结点********
1 a
3 c
4 d
6 f
7 g
*/追问

【1】那里不是特明白...creat那里为什么要head=NULL呢,然后下面依然head=p...不是等于前面白赋值了么..直接就把print函数里面*p初始化不就可以运行成功了吗....望解答..谢谢~

追答

【1】里面说的很清楚了啊!
你原来的 creat 函数中认为链表是有一个表头节点的,也就是链表的第一节点是 head->next,
而不是 head。
但是下面的 solve 函数和 print 函数都认为链表是没有表头节点的,也就是他们认为链表的
第一个节点是:head 而不是 head->next 。

这两个是有矛盾的,两个地方要修改一个地方,这里是修改了 creat 函数。

head=NULL 是初始化为一个空的链表,比如 第一就输入: 0 0 ,
那么 while(!(p->num == 0 && strcmp(p->name,"0")==0)) 这个循环里面的语句都不会执行,
head 就应该是 NULL 。

温馨提示:答案为网友推荐,仅供参考
第1个回答  2011-09-15
#include <stdio.h>
#include <stdlib.h>
#define N 10
typedef struct student
{
int num;
float score;
struct student *next;
}STU;

STU *create()
{
int i;
STU *p,*head=NULL,*tail=head;
for (i=0;i<N;i++)
{
p=(STU *)malloc(sizeof(STU));
scanf("%d%f",&p->num,&p->score);
p->next=NULL;
if (p->num<0)
{
free(p);
break;
}
if(head==NULL)
head=p;
else
tail->next=p;
tail=p;
}
return head;
}

void output(STU *p)
{
while (p!=NULL)
{
printf("%d\t%.2f\n",p->num,p->score);
p=p->next;
}
}

STU *del(STU *a,STU *b)
{
STU *head,*p1,*p2;
p1=p2=head=a; //让p1、p2、head结点指向链表a的头部
while (b!=NULL)
{
p1=p2=head; //每次循环前让p1、p2始终指向删除后链表的头部
while (p1!=NULL)
{
if (b->num==p1->num) //学号相同,删除结点信息
if(p1==head) //如果删除的是头结点,则头结点位置要后移
{
head=p1->next;
free(p1);
p1=p2=head;
}
else //如果删除的是中间结点
{
p2->next=p1->next;
free(p1);
p1=p2->next;
}
else //学号不同,则p1,p2指针依次后移
{
p2=p1;
p1=p1->next;
}
}
b=b->next;
}
return head;
}

int main(int argc, char *argv[])
{
STU *a,*b,*c;
printf("\n请输入链表a的信息,学号小于零时结束输入:格式(学号 成绩)\n");
a=create();
printf("\n请输入链表b的信息,学号小于零时结束输入:格式(学号 成绩)\n");
b=create();
system("cls");
printf("\n链表a的信息为:\n");
output(a);
printf("\n链表b的信息为:\n");
output(b);
c=del(a,b);
printf("\n删除后的链表信息为:\n");
output(c);

return 0;
}

这里有一个程序:有两个链表a和b,设结点中包含学号、姓名。从a链表中删去与b链表中有相同学号的那些结点。
我编写的代码如下:
struct student * Delete(struct student *head1,struct student *head2)
{
struct student *pa,*qa,*pb;
pa=qa=head1;
pb=head2;
while(pa!=NULL)//对于链表a中的每个元素
{
pb=head2;
//与链表b中的每个元素对比

while((pb!=NULL)&&(pa->num != pb->num))
pb=pb->next;
if(pa->num==pb->num)
{
if(pa==head1)
{
head1=pa->next;
pa=qa=head1;
}
else
{
qa->next=pa->next;
pa=pa->next;
}
}
qa=pa;
pa=pa->next;
}
return head1;
}
每次运行到pb=pb->next;时都会出现问题,是最后pb指向空指针,要怎么解决这个问题,请各位大虾帮忙解决以下……追问

while((pb!=NULL)&&(pa->num != pb->num))
//这里应该是while((pb->next!=NULL)&&(pa->num != pb->num))

不然b链表循环到最后一个元素的时候如果这个元素不跟a链表当中有相同学号,那么依然会执行pb=pb->next; 使得pb指向空指针;
紧接着你下面的判断语句if(pa->num==pb->num) 这个时候PB指向空地址,读取不出pb->num这个值,就会报错

第2个回答  2011-09-14
我修改的代码。

#include <stdio.h>
#include <malloc.h>

struct student
{
int num;
char name[10];
struct student *next;
};

void main()
{
void print(struct student *head);
struct student *creat();
struct student *solve(struct student *head_a,struct student *head_b);
struct student *head,*head_a,*head_b;
head_a=creat();
head_b=creat();

head=solve(head_a,head_b);
print(head);

}

struct student *creat()
{
struct student *head,*p,*p1;
p1=(struct student *)malloc(sizeof(struct student));
head=p=p1;
head->next=NULL;//修改地点:很重要。
printf("输入学号和姓名0停止接收数据\n");
printf("请输入学生学号和姓名:");
scanf("%d %s",&p->num,&p->name);
while(p->num!=0)
{
printf("请输入学生学号和姓名:");
p=(struct student *)malloc(sizeof(struct student));
p1->next=p;
p->next=NULL;
scanf("%d %s",&p->num,&p->name);
p1=p1->next;
}
return head;
}

struct student *solve(struct student *head_a,struct student *head_b)
{
struct student *p,*p1,*t;
p=p1=head_a;
t=head_b;
while(p!=NULL)
{
t=head_b;
while(t->next!=NULL&&(t->num!=p->num))//遍历B。
{
t=t->next;
}
if(t->num==p->num)
{
if(p==head_a)
{
head_a=head_a->next;
p1=p=head_a;
}
else
{
p1->next=p->next;
p=p->next;
}

}
else
{
p1=p;
p=p->next;
}
}
return head_a;
}
void print(struct student *head)
{
struct student *p=head;
while(p!=NULL)
{
printf("%d %s\n",p->num,p->name);
p=p->next;
}
}

creat那里感觉你写的逻辑性不是很强,我的写的这个比较标准一点。
还有一些重要的初始化,你没做。
再就是排版了,当然这个不是很重要,但是看着漂亮。追问

head->next=NULL;//修改地点:很重要。

为什么很重要?

第3个回答  2011-09-14
void print(struct student *head)
{
struct student *p;

while(p!=NULL)
{
printf("%d %s\n",p->num,p->name);
p=p->next;

}

}
在上面这个函数里,定义了一个野指针p, 指针必须要初始化,不然就成了野指针,可止向任一地方,价格初始化就好了,struct student *p = head;
第4个回答  2011-09-14
你的print函数有问题,指针p没有被初始化,那么你的p->num,p->name就没有值,所以会出错,正确写法应该把head指针赋给p,即struct student *p=head
相似回答