说明结构变量有以下三种方法。以上面定义的stu为例来加以说明。 1. 先定义结构,再说明结构变量。如: struct stu { int num; char name[20]; char sex; float score; }; struct stu boy1,boy2; 说明了两个变量boy1和boy2为stu结构类型。也可以用宏定义使一个符号常量来表示一个结构类型,例如: #define STU struct stu STU { int num; char name[20]; char sex; float score; }; STU boy1,boy2;
2. 在定义结构类型的同时说明结构变量。例如: struct stu { int num; char name[20]; char sex; float score; }boy1,boy2;
在图7.3中,第0个结点称为头结点, 它存放有第一个结点的首地址,它没有数据,只是一个指针变量。 以下的每个结点都分为两个域,一个是数据域,存放各种实际的数据,如学号num,姓名name,性别sex和成绩score等。另一个域为指针域, 存放下一结点的首地址。链表中的每一个结点都是同一种结构类型。例如, 一个存放学生学号和成绩的结点应为以下结构: struct stu { int num; int score; struct stu *next; } 前两个成员项组成数据域,后一个成员项next构成指针域, 它是一个指向stu类型结构的指针变量。链表的基本操作对链表的主要操作有以下几种: 1.建立链表; 2.结构的查找与输出; 3.插入一个结点; 4.删除一个结点; 下面通过例题来说明这些操作。 [例7.10]建立一个三个结点的链表,存放学生数据。 为简单起见, 我们假定学生数据结构中只有学号和年龄两项。 可编写一个建立链表的函数creat。程序如下: #define NULL 0 #define TYPE struct stu #define LEN sizeof (struct stu) struct stu { int num; int age; struct stu *next; }; TYPE *creat(int n) { struct stu *head,*pf,*pb; int i; for(i=0;i<n;i++) { pb=(TYPE*) malloc(LEN); printf("input Number and Age"); scanf("%d%d",&pb->num,&pb->age); if(i==0) pf=head=pb; else pf->next=pb; pb->next=NULL; pf=pb; } return(head); } 在函数外首先用宏定义对三个符号常量作了定义。这里用TYPE表示struct stu,用LEN表示sizeof(struct stu)主要的目的是为了在以下程序内减少书写并使阅读更加方便。结构stu定义为外部类型,程序中的各个函数均可使用该定义。
[例7.11]写一个函数,在链表中按学号查找该结点。 TYPE * search (TYPE *head,int n) { TYPE *p; int i; p=head; while (p->num!=n && p->next!=NULL) p=p->next; /* 不是要找的结点后移一步*/ if (p->num==n) return (p); if (p->num!=n&& p->next==NULL) printf ("Node %d has not been found!",n } 本函数中使用的符号常量TYPE与例7.10的宏定义相同,等于struct stu。函数有两个形参,head是指向链表的指针变量,n为要查找的学号。进入while语句,逐个检查结点的num成员是否等于n,假如不等于n且指针域不等于NULL(不是最后结点)则后移一个结点,继续循环。如找到该结点则返回结点指针。 如循环结束仍未找到该结点则输出“未找到”的提示信息。
[例7.12]写一个函数,删除链表中的指定结点。删除一个结点有两种情况: 1. 被删除结点是第一个结点。这种情况只需使head指向第二个结点即可。即head=pb->next。其过程如图7.5所示。 2. 被删结点不是第一个结点,这种情况使被删结点的前一结点指向被删结点的后一结点即可。即pf->next=pb->next。其过程如图7.6所示。 函数编程如下: TYPE * delete(TYPE * head,int num) { TYPE *pf,*pb; if(head==NULL) /*如为空表, 输出提示信息*/ { printf("empty list!"); goto end;} pb=head; while (pb->num!=num && pb->next!=NULL) /*当不是要删除的结点,而且也不是最后一个结点时,继续循环*/ /*pf指向当前结点,pb指向下一结点*/ if(pb->num==num) {if(pb==head) head=pb->next; /*如找到被删结点,且为第一结点,则使head指向第二个结点, 否则使pf所指结点的指针指向下一结点*/ else pf->next=pb->next; free(pb); printf("The node is deleted");} else printf("The node not been foud!"); end: return head; } 函数有两个形参,head为指向链表第一结点的指针变量,num删结点的学号。 首先判定链表是否为空,为空则不可能有被删结点。若不为空,则使pb指针指向链表的第一个结点。进入while语句后逐个查找被删结点。找到被删结点之后再看是否为第一结点,若是则使head指向第二结点(即把第一结点从链中删去),否则使被删结点的前一结点(pf所指)指向被删结点的后一结点(被删结点的指针域所指)。如若循环结束未找到要删的结点, 则输出“末找到”的提示信息。最后返回head值。
[例7.13]写一个函数,在链表中指定位置插入一个结点。在一个链表的指定位置插入结点, 要求链表本身必须是已按某种规律排好序的。例如,在学生数据链表中, 要求学号顺序插入一个结点。设被插结点的指针为pi。 可在三种不同情况下插入。 1. 原表是空表,只需使head指向被插结点即可。见图7.7(a) 2. 被插结点值最小,应插入第一结点之前。这种情况下使head指向被插结点,被插结点的指针域指向原来的第一结点则可。即:pi->next=pb; head=pi; 见图7.7(b) 3. 在其它位置插入,见图7.7(c)。这种情况下,使插入位置的前一结点的指针域指向被插结点,使被插结点的指针域指向插入位置的后一结点。即为:pi->next=pb;pf->next=pi; 4. 在表末插入,见图7.7(d)。这种情况下使原表末结点指针域指向被插结点,被插结点指针域置为NULL。即: pb->next=pi; pi->next=NULL; TYPE * insert(TYPE * head,TYPE *pi) { TYPE *pf,*pb; pb=head; if(head==NULL) /*空表插入*/ (head=pi; pi->next=NULL;} else { while((pi->num>pb->num)&&(pb->next!=NULL)) {pf=pb; pb=pb->next; }/*找插入位置*/ if(pi->num<=pb->num) {if(head==pb)head=pi;/*在第一结点之前插入*/ else pf->next=pi;/*在其它位置插入*/ pi->next=pb; } else /*在表末插入*/ } return head;} 本函数有两个形参均为指针变量,head指向链表,pi 指向被插结点。函数中首先判定链表是否为空,为空则使head指向被插结点。表若不空,则用while语句循环查找插入位置。找到之后再判定是否在第一结点之前插入,若是则使head 指向被插结点被插结点指针域指向原第一结点,否则在其它位置插入, 若插入的结点大于表中所有结点,则在表末插入。本函数返回一个指针, 是链表的头指针。 当插入的位置在第一个结点之前时, 插入的新结点成为链表的第一个结点,因此head的值也有了改变, 故需要把这个指针返回主调函数。 [例7.14]将以上建立链表,删除结点,插入结点的函数组织在一起,再建一个输出全部结点的函数,然后用main函数调用它们。 #define NULL 0 #define TYPE struct stu #define LEN sizeof(struct stu) struct stu { int num; int age; struct stu *next; }; TYPE * creat(int n) { struct stu *head,*pf,*pb; int i; for(i=0;i<n;i++) { pb=(TYPE *)malloc(LEN); printf("input Number and Age"); scanf("%d%d",&pb->num,&pb->age); if(i==0) pf=head=pb; else pf->next=pb; pb->next=NULL; pf=pb; } return(head); } TYPE * delete(TYPE * head,int num) { TYPE *pf,*pb; if(head==NULL) { printf("empty list!"); goto end;} pb=head; while (pb->num!=num && pb->next!=NULL)
if(pb->num==num) { if(pb==head) head=pb->next; else pf->next=pb->next; printf("The node is deleted"); } else free(pb); printf("The node not been found!"); end: return head; } TYPE * insert(TYPE * head,TYPE * pi) { TYPE *pb ,*pf; pb=head; if(head==NULL) { head=pi; pi->next=NULL; } else { while((pi->num>pb->num)&&(pb->next!=NULL)) { pf=pb; pb=pb->next; } if(pi->num<=pb->num) { if(head==pb) head=pi; else pf->next=pi; pi->next=pb; } else { pb->next=pi; pi->next=NULL; } } return head; } void print(TYPE * head) { printf("Number Age"); while(head!=NULL) { printf("%d %d",head->num,head->age); head=head->next; } } main() { TYPE * head,*pnum; int n,num; printf("input number of node: "); scanf("%d",&n); head=creat(n); print(head); printf("Input the deleted number: "); scanf("%d",&num); head=delete(head,num); print(head); printf("Input the inserted number and age: "); pnum=(TYPE *)malloc(LEN); scanf("%d%d",&pnum->num,&pnum->age); head=insert(head,pnum); print(head); }