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();
}