1.创建一个链表
通过上述代码可以建立一条长度为n 的链表,实现流程如下:
(1)用maloc()函数在内存的动态存储区中创建一块大小为sizeof(LNode)的空间,并将
其地址赋值给LinkList类型变量p (LinkList为指向LNode变量的类型,LNode为前面定义
的链表结点类型)。然后将数据e存入该结点的数据域data,
指针域存放NULL,其中数据e由函数Get()获得。
(2)如果指针变量list为空,则说明本次生成的结点是第一个结点,
为此将p赋值给list。变量list 是LinkList类型的,只用来指向第-个链表结点,
因此它是该链表的头指针,最后要返回。
(3)如果指针变量list不为空,则说明本次生成的结点不是第1个结点,所以要将p赋
值给r->next.在此变量r是一个LinkList类型,永远指向原先链表的最后一个结点,也就是
要插入结点的前一个结点。
(4)再将p赋值给r,目的是使r再次指向最后的结点,以便生成链表的下一个结点,
这样能够保证r永远指向原先链表的最后一个结点。
(5)最后,将生成的链表的头指针list 返回主调函数,通过list就可以访问到该链表的
每一个结点,并对该链表进行操作。
2.向链表中插入结点
在指针q指向的结点后面插入结点的流程如下:
(1)首先生成一个新的结点,大小为sizeof(LNode),用LinkList类型的变量p指向该结点,
并将该结点的数据域赋值为e。
(2)然后判断链表是否为空。如果链表为空,则将p赋值给list,p的next域的值置为
空;如果链表不为空,将q指向结点next域的值赋给p指向结点的nextyu,这样p指向
的结点就与q指向结点的下一个结点链接到了一起
(3)接下来将p的值赋值给q所指向结点的next域,这样就将p指向的结点插入到了指
针q指向结点的后面。
要从非空链表中删除q所指的结点,需要从如下3种情况情形来考虑。
(1)q所指结点是链表的第一个结点。
当q所指向的链表是第一个结点时,只需将q所指结点的指针域next的值赋值给头
指针list,让list指向第二个结点,然后再释放掉q所指向结点即可实现。
(2)q所指结点的前驱结点的指针是已知的。
当q所指结点的前驱结点的指针是已知时,在此假设为r,只需将q所指结点的指针域
next的值赋值给r的指针域next,然后释放掉q所指结点即可实现。
以上两种情形可用下面的代码来描述
q所指结点的前驱结点的指针是未知时,需要先通过链表头指针list遍历链表,找到q的前驱结点的指针,
并将指针赋值给指针变量r,再按照第二种情形取做即可实现。
实现流程如下:
(1)将链表*list的内容赋值给p,这样因为p指向链表的第一个结点而成为了链表的表头。
(2)只要p不为空(NULL),就将p指向的下一个结点的指针(地址)赋值给q,并使用函数
free()稀释掉p所指向的结点,p再指向下一个结点。重复上述循环,直到链表为空为止。
(3)最后将链表*list的内容置为空(NULL),此时主函数中的链表list就变为空,这样
防止list成为野指针,并且链表在内存中也被完全稀释掉了
通过上述代码可以建立一条长度为n 的链表,实现流程如下:
(1)用maloc()函数在内存的动态存储区中创建一块大小为sizeof(LNode)的空间,并将
其地址赋值给LinkList类型变量p (LinkList为指向LNode变量的类型,LNode为前面定义
的链表结点类型)。然后将数据e存入该结点的数据域data,
指针域存放NULL,其中数据e由函数Get()获得。
(2)如果指针变量list为空,则说明本次生成的结点是第一个结点,
为此将p赋值给list。变量list 是LinkList类型的,只用来指向第-个链表结点,
因此它是该链表的头指针,最后要返回。
(3)如果指针变量list不为空,则说明本次生成的结点不是第1个结点,所以要将p赋
值给r->next.在此变量r是一个LinkList类型,永远指向原先链表的最后一个结点,也就是
要插入结点的前一个结点。
(4)再将p赋值给r,目的是使r再次指向最后的结点,以便生成链表的下一个结点,
这样能够保证r永远指向原先链表的最后一个结点。
(5)最后,将生成的链表的头指针list 返回主调函数,通过list就可以访问到该链表的
每一个结点,并对该链表进行操作。
LinkList GreatLinkList(int n) { //建立一个长度为n的链表 LinkList p,r,list=NULL; ElemType e; int i; for(i=1;i<=n;i++) { Get(e); p=(LinkList)malloc(sizeof(LNode)); p->data=e; p->next=NULL; if(!list) list=p; else r->next=p; r=p; } return list; }
2.向链表中插入结点
在指针q指向的结点后面插入结点的流程如下:
(1)首先生成一个新的结点,大小为sizeof(LNode),用LinkList类型的变量p指向该结点,
并将该结点的数据域赋值为e。
(2)然后判断链表是否为空。如果链表为空,则将p赋值给list,p的next域的值置为
空;如果链表不为空,将q指向结点next域的值赋给p指向结点的nextyu,这样p指向
的结点就与q指向结点的下一个结点链接到了一起
(3)接下来将p的值赋值给q所指向结点的next域,这样就将p指向的结点插入到了指
针q指向结点的后面。
void insertList(LinkList *list,LinkList q,ElemType e) { //向链表中由指针q指出的结点后面插入结点,结点数据为e LinkList p; p=(LinkList)malloc(sizeof(LNode)); //生成一个新的结点,由p指向它 p->data=e; //向该结点的数据域赋值e if(!*list) { *list=p; p->next=NULL; } else //当链表为空时 { p->next=q->next; //将q指向的结点next域的值赋值给p指向结点的next域 q->next=p; //将p的值赋值给q的next域 } }3.从链表中删除结点
要从非空链表中删除q所指的结点,需要从如下3种情况情形来考虑。
(1)q所指结点是链表的第一个结点。
当q所指向的链表是第一个结点时,只需将q所指结点的指针域next的值赋值给头
指针list,让list指向第二个结点,然后再释放掉q所指向结点即可实现。
(2)q所指结点的前驱结点的指针是已知的。
当q所指结点的前驱结点的指针是已知时,在此假设为r,只需将q所指结点的指针域
next的值赋值给r的指针域next,然后释放掉q所指结点即可实现。
以上两种情形可用下面的代码来描述
void delLink(LinkList *list,LinkList r,LinkList q) { if(q==*list) //删除链表结点的第一种情形 *list=q->next; else r->next=q->next; //删除链表结点的第二种情形 free(q); }(3)q所指结点的前驱结点的指针是未知的。
q所指结点的前驱结点的指针是未知时,需要先通过链表头指针list遍历链表,找到q的前驱结点的指针,
并将指针赋值给指针变量r,再按照第二种情形取做即可实现。
void delLink(LinkList *list,LinkList q) { LinkList r; if(q==list) { *list=q->next; free(q); } else { for(r=*list;r->next!=q;rr=r->next); //遍历链表,找到q的前驱结点的指针 if(r->next!=NULL) { r->next=q->next; free(q); } } }4.销毁一个链表
实现流程如下:
(1)将链表*list的内容赋值给p,这样因为p指向链表的第一个结点而成为了链表的表头。
(2)只要p不为空(NULL),就将p指向的下一个结点的指针(地址)赋值给q,并使用函数
free()稀释掉p所指向的结点,p再指向下一个结点。重复上述循环,直到链表为空为止。
(3)最后将链表*list的内容置为空(NULL),此时主函数中的链表list就变为空,这样
防止list成为野指针,并且链表在内存中也被完全稀释掉了
void destroyLinkList(LinkList *list) { LinkList p,q; p=*list; while(p) { q=p->next; free(p); p=q; } *list=NULL; }链表操作实现
#include<stdio.h> typedef struct { char key[15]; //关键字 char name[20]; int age; }DATA; #include "2-4 ChainList.h" #include "2-5 ChainList.c" void ChainListAll(ChainListType *head) //遍历链表 { ChainListType *h; DATA data; h=head; printf("链表所有数据如下:\n"); //循环处理链表每个结点 while(h) { data=h->data; //获取结点数据 printf("(%s,%s,%d)\n",data.key,data.name,data.age); h=h->next; //处理下一个结点 } } void main() { ChainListType *node,*head=NULL; DATA data; char key[15],findkey[15]; printf("输入链表中的数据,包括关键字,姓名,年龄,关键字输入0则退出:\n"); do{ fflush(stdin); //清空输入缓冲区 scanf("%s",data.key); if(strcmp(data.key,"0")==0) break; //若输入0则退出 scanf("%s%d",data.name,&data.age); head=ChainListAllEnd(head,data); //在链表尾部添加结点数据 }while(1); printf("该链表共有%d个结点。\n",ChainListLength(head)); //返回结点数量 ChainListAll(head); //显示所有结点 printf("\n插入结点,输入插入位置的关键字:"); scanf("%s",&findkey); //输入插入位置的关键字 printf("输入插入结点的数据(关键字 姓名 年龄):"); scanf("%s%s%d",data.key,data.name,&data.age); //输入插入结点的数据 head=ChainListInsert(head,findkey,data); //调用插入函数 ChainListAll(head); //显示所有结点 printf("\n在链表中查找,输入查找关键字:"); fflush(stdin); //清空输入缓冲区 scanf("%s",key); //输入查找关键字 node=ChainListFind(head,key); //调用查找幻术,返回结点指针 if(node) //若返回结点指针有效 { data=node->data; //获取结点的数据 printf("关键字%s对应的结点数据为(%s,%s,%d)\n",key,data.key,data.name,data.age); } else //若指针无效 { printf("在链表中未找到关键字%s的结点!\n",key); } printf("\n在链表中删除结点,输入要删除的关键字:"); fflush(stdin); //清空输入缓冲区 scanf("%s",key); //输入删除结点的关键字 ChainListDelete(head,key); //调用删除结点函数 ChainListAll(head); //显示所有结点 getchar(); }