例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 *p1,*p2;
if (head==NULL){printf("\nlist null!\n");return (head);}
p1=head;
while(num!=p1->num && p1->next!==NULL) /*p1指向的不是所要找的结点,并且后面还有结点/
{p2=p1;p1=p1->next;}/p1后移一个结点 */
  if(num==p1->num) /找到了*/
  {if(p1==head)head=p1->next;/若p1指向的是首结点,把第二个结点地址赋予head/
    else p2->next=p1->next;
/*否则将下一结点地址赋给前一结点地址*/
printf("delete:%ld\n",num);
 n=n-1;
}
  else printf("%ld not been found!\n",num); /找不到该结点/ 
  return(head);
}
函数的类型是指向struct student类型数据的指针,它的值是链表的头指针。函数参数为head和要删除的学号num。head的值可能在函数执行过程中被改变(当删除第一个结点时)。