5 输出链表
将链表中各结点的数据依次输出。这个问题比较容易处理。例11.7中已初步介绍了出链表的方法。首先要知道链表第一个结点的地址,也就是要知道head的值。然后设一个指针变量p,先指向第一个结点,输出p所指的结点,然后使p后移一个结点,再输出。
到链表的尾结点。
例11.9编写一个输出链表的函数print。
void print (struct student * head)
{struct student * p;
printf("\nNow,These %d records are:\n",n);
p=head;
if (head!=NULL)
do
{printf(" %ld %5. 1f\n" ,p->num,p->score);
p=p->next;
}while(p!=NULL);
}
算法可用图11.17表示。其过程可用图11.18表示。p先指向第一结点,在输出完第一个结点之后,p移到图中p虚线位置,指向第二个结点。程序中"p=p->next"的作用是将p原来所指向的结点中next的值赋给p,而p->next的值就是第二个结点的起始地址。将它赋给p,就是使p指向第二个结点。
head 的值由实参传过来,也就是将已有的链表的头指针传给被调用的函数,在 print函数中从head所指的第一个结点出发顺序输出各个结点。
6 对链表的删除操作
已有一个链表,希望删除其中某个结点。怎样考虑此问题的算法呢?先打个比方:一队小孩(A、B、C、D、E)手拉手,如果某一小孩(C)想离队有事,而队形仍保持不变。只要将 C的手从两边脱开,B改为与D拉手即可,见图11.19。图11.19(a)是原来的队伍,图11.19(b)是C离队后的队伍。
与此相仿,从一个动态链表中删去一个结点,并不是真正从内存中把它抹掉,而是把它从链表中分离开来,只要撤消原来的链接关系即可。
例11.10 写一函数以删除动态链表中指定的结点。
以指定的学号作为删除结点的标志。例如,输人99103表示要求删除学号为99103的结点。解题的思路是这样的:从p指向的第一个结点开始,检查该结点中的num值是否等于输人的要求删除的那个学号。如果相等就将该结点删除,如不相等,就将p后移一个结点,再如此进行下去,直到遇到表尾为止。
可以设两个指针变量p1和p2,先使p1指向第一个结点(图11.20(a))。如果要删除的不是第一个结点,则使p1后指向下一个结点(将p1->next 赋给 p1),在此之前应将p1的值赋给p2,使p2指向刚才检查过的那个结点,见图11.20(b)。如此一次一次地使 p后移,直到找到所要删除的结点或检查完全部链表都找不到要删除的结点为止。如果找到某一结点是要删除的结点,还要区分两种情况:①要删的是第一个结点(p1的值等于 head 的值,如图11.20(a)那样),则应将p1->next赋给head。见图11.20(c)。这时head指向原来的第二个结点。第一个结点虽然仍存在,但它已与链表脱离,因为链表中没有一个结点或头指针指向它。虽然p1还指向它,它仍指向第二个结点,但仍无济于事,现在链表的第一个结点是原来的第二个结点,原来第一个结点已“丢失”,即不再是链表中的一部分了。②如果要删除的不是第一个结点,则将p1->next 赋给p2->next,见图11.20(d).p2->next原来指向p1指向的结点(图中第二个结点),现在p2->next改为指向p1 ->next所指向的结点(图中第三个结点)。p1所指向的结点不再是链表的一部分。
还需要考虑链表是空表(无结点)和链表中找不到要删除的结点的情况。
图11.21表示解此题的算法。
删除结点的函数 del 如下:
struct student * del (struct student* head ,long num)
{struct student * pl,*p2;
if (head==NULL){printf("\nlist null! \n");goto end;}
pl=head;
while(num! =p1->num &&.p1->next!==NULL)
/*p1指向的不是所要找的结点,并且后面还有结点*/
{p2=pl;p1=pl->next;} /*p1后移一个结点*/
if(num==pl->num) /*找到了*/
{if(p1==head)head=p1->next;
/*若pI指向的是首结点,把第二个结点地址赋予head*/
else p2->next=pl->next;
/*否则将下一结点地址赋给前一结点地址*/
printf("delete:%ld\n",num);
n=n-1;
}
else printf(" %ld not been found! \n",num);/*找不到该结点*/
return(head);
}
函数的类型是指向struct student类型数据的指针,它的值是链表的头指针。函数参数为 head 和要删除的学号num.head的值可能在函数执行过程中被改变(当删除第一个结点时)。