一、单链表
(1)头插法
#include<stdio.h>
#include<stdlib.h>
struct Book//一个单链表的声明(结构体内包括信息域成员,和下一个节点的指针/地址)
{
char title[128];//title"标题“
char author[40];//author”作家“
struct Book *next;//下一个节点的指针(地址)
};
void getInput(struct Book *book)//传入新的节点的地址 ,以达到给新节点赋值的目的,在函数外部赋值需要传入数据所在的地址
{
printf("请输入书名:");
scanf("%s",book->title);//指针指向结构体成员使用->
printf("请输入作者:");
scanf("%s",book->author);
}
void addBook(struct Book **library)//添加新的节点(头插法)//头插法,插入节点,是把头指针的地址改了,也就是把指向头指针的指针改了,所以我们需要对传入的头指针进行解引用,找到指向头指针的指针,并修改它;(头指针只是一个存放第一个节点的地址的指针变量)
{// void addBook(struct Book *library)改的是存放在library里的数据,void addBook(struct Book **library)才能修改指针本身的地址,指针本身的地址才是第一个节点的地址;
struct Book *book,*temp;//*book,创建了我们需要添加的节点的指针/地址名(只是一个声明) ;*temp,意为”临时工“,一般作为空的临时变量使用
book=(struct Book *)malloc(sizeof(struct Book));//给新添加的指针分配地址:(数据类型)malloc(所申请的数据长度) --> (数据类型)malloc(sizeof(数据类型))
if(book==NULL)//如果book==NULL也就是内存分配失败的话,我们给出提醒,并终止整个程序
{
printf("内存分配失败!\n");
exit(1);// exit()是个函数,意为“出口”,需要头文件#include<stdlib.h>, 传入1表示程序异常,立即终止;传入0则表示程序正常运行;
}
getInput(book);//自定义函数,意为“获取输入”,让用户填入新节点的信息(填充信息域),传入book ,相当于把 struct Book *book=右边的值送过去赋值
//有两种情况,头指针一开始是指向NULL的,也就是说这是一个空链表;还有一种情况,头指针是指向节点的,这不是一个空链表;
if(*library!=NULL)//不是空链表时
{
temp=*library;//先把头指针中存放的原第一个节点的地址保存在临时变量temp中
*library=book;//然后把头指针指向新的第一个节点的地址
book->next=temp;//最后把新的第一个节点的结构体成员(也就是存放下一个节点地址的地方)指向原第一个节点的地址
}
else//是空链表时
{
*library=book;//把头指针指向新添加的节点的地址
book->next=NULL;//然后把新添加的节点中的结构体成员(结构体中的指针域)指向NULL
}
}
void printlibrary(struct Book *library)//打印链表内容
{
struct Book *book;//新指针,跟其他的重名但其实无关,是个只存在于printlibrary函数内的新的指针变量
int count=1;//计数器
book=library;//用新的指针变量来拷贝头指针(保证接下来的操作不会修改到真正的头指针)
while(book!=NULL)//这个循环用来遍历链表,从头指针一直指向下一个节点,直到指向NULL时表示链表结束,停止循环
{
printf("Book%d:",count);//记录这是第几本书
printf("书名:%s",book->title);
printf("作者:%s",book->author);
book=book->next;//把下一个节点的地址给book,循环继续
count++;
}
}
void releaselibrary(struct Book **library)//release意为“释放”,这个函数用来释放链表,所以我们传入头指针
{
struct Book *temp;//定义一个临时变量来保留头指针
while(*library!=NULL)//只要这个链表的头指针不指向NULL,也就是说它不是一个空链表时,我们就要进行以下步骤释放链表占用的内存空间
{
temp=*library;
*library=(*library)->next;//指向下一个节点
free(temp);//free()函数,用来手动释放我们手动申请的动态内存空间
}
}
int main()
{
int ch;
struct Book *library=NULL;//创建了头指针,并且指向NULL说明是一个空的头指针,也就是一个空的链表;
//addBook(&library);//传入头指针的地址,然后就可以在addBook函数内修改头指针所指向的数据(把NULL改了)
while(1)//进入死循环,不断的询问是否要录入信息,直到用户输入正确
{
printf("请问是否需要录入书籍信息(Y/N):");
do//不管三七二十一,输入一次
{
ch=getchar();//getchar()函数获取单个字符
}while(ch!='Y'&&ch!='N');//跳出循环的条件是输入正确
if(ch=='Y')//如果想输入,就把头指针传过去
{
addBook(&library);
}
else//不想输入就退出死循环
{
break;
}
}
printf("请问是否需要打印图书信息(Y/N):");//询问用户是否需要查看图书信息
do
{
ch=getchar();
}while(ch!='Y'&&ch!='N');
if(ch=='Y')//如果要就进入打印链表的函数
{
printlibrary(library);
}
releaselibrary(&library);//最后手动释放链表,因为链表可能都是通过malloc函数申请的动态内存空间,不自动释放的话会一直占用内存空间
return 0;
}