苦读诗书后理解的链表内容,真的很有用!精华满满全程无尿点!
链表的构成是学生的姓名、学号、成绩(为求简化,只选择三项)
链表的理解
主要目的实现链表的基本功能: 增、删、改、查;
增:头插法或者尾插法构建链表;
(本人认为链表的构建,主要就是构建一个带着数据和指针的结构体,数据部分储存需要的数据,然后通过改变指针的指向,来将多个储存在计算机内存不同位置的结构体数据串联起来)
第一步:初始化链表
定义首元结点,头结点存储数据为空,指针指向首元结点
//链表的初始化
LinkList InitList()
{
LinkList head;//头结点变量
head = (Node*)malloc(sizeof(Node));//动态分配内存
head -> next = NULL;//头结点指针域为空
return head;//返回头结点地址,即头指针
}
头插法
如果是头插法,其主要目的就是不断添加在首元结点和头结点之间;因此,改变指针指向的思路便是--新构建的结点指针指向应该是原来头结点指针所指向的结点地址,此时此刻,头结点和新建结点所指向的应该是同一个结点(这只是我本人的个人观点,没有在代码中验证过,只是单纯的理论分析,小白,勿伤);因此下一步需要改变头结点指针指向,指向新建结点,实现头插法添加。
//头插法创建链表
void CreateByHead(LinkList head)
{
Node *s;
char name[20];
int number;
printf("请输入学生的姓名、学号\n");
while(1){
scanf("%s",name);
scanf("%d",&number);
if(number==0){
break;
}
s = (Node*)malloc(sizeof(Node));
strcpy(s->name,name);
s->number = number;
s->next = head->next;//新建结点指向原来的首元结点
head -> next = s; //链表的头结点指向新建结点
}
}
尾插法
如果是尾插法,则其主要目的就是不断添加在尾节点之后,其后永远链接着NULL(空指针),因此构建链表的主要思路就是--尾结点的指针指向永远是新创建结点的地址,(听起来比头插法少一点,其实实际体验下来,并没有差多少,甚至问哦个人觉得没有头插法方便)
由于现在不是头结点同时需要不断变换,所以尾插法需要声明两个结构体指针,一个用来构建新结点,另一个则用来表示插入前的尾结点。
在尾结点的指针指向新建结点后,此时的尾结点就应该是新建结点了,所以将新建结点的地址赋给用来纸指向“尾结点”的机构体指针,最后在循环外将尾结点储存的指针指向NULL。
//尾插法构建链表
void CreatByRear(LinkList head){
Node *r,*s;
char name[20];
int number;
r = head;
printf("请输入学生的姓名学号:\n");
while(1){
scanf("%s",name);
scanf("%d",&number);
if(number == 0){
break;
}
s = (Node*)malloc(sizeof(Node));
strcpy(s->name,name);
s->number = number;
r->next = s;//原来的尾结点指向新建结点
r = s;//r指向新结点(r指向链表末尾)
}
r->next = NULL;//尾结点的指针为空
}
删:顾名思义删除结点
指针区别于数组,就在于它的储存并不是按照一定顺序,而是依靠指针来构成连接;
明白这点后就可以很简单的知道链表的删除了!
使用查找找到需要删除的结点后,将前结点指针指向后结点,将这个结点跳过去,随后释放结点。
//单链表的删除
void Delete(LinkList head,int pos){
Node *p = head,*q;//q用来释放内存
int j=0;
printf("**********删除第%d个学生***************\n",pos);
while(p&&j<pos-1){ // 通过循环找到pos-1个结点,可以改变为姓名查找
p=p->next;
j++;
}
if(p==NULL||p->next==NULL){//第pos个结点不存在
printf("the pos is error");
}else {
q = p->next;//q指向第pos个结点
p->next = q->next;//连接删除结点两边的结点
free(q); //释放要删除的结点
}
}
改:就是找到目标结点后修改数据
改本身没什么可说的,重点其实是在查上面
//偷个小懒,就使用管理系统中的删除操作了
void change(LinkList head,char name[]){
LinkList p;
p = head->next;
while(p)
{
if(strcmp(p->name,name)!=0) p = p->next;
else break;
}
if(p==NULL){
printf("查无此人,操作失败\n");
}else {
printf("输入修改后的学生姓名、学号、成绩\n");
scanf("%s%d%d",p->name,&p->number,&p->score);
}
}
查:个人认为是很有的说的一点
首先就是最重要的一点,查找操作返回的是结构体指针!!!!目的就是找到后方便操作
废话不多说,上!代!码!
(摸鱼好爽,所以我还选择用操作系统里的代码)
STD *search(LinkList head,char name[]){
LinkList s;
s = head->next;
while(s)
{
if(strcmp(s->name,name)!=0) s= s->next;
else break;
}
if(s == NULL) printf("没有找到");
return s;
}
查找本身没什么说道的,重点还是与其他功能的联合操作
其他操作:显示,升降序排序
显示:很简单的操作,只需要定义一个结构体指针,指向首元结点,然后打印其中的数据部分,随后指针后移,直到指向空指针NULL
3 2 1 上代码!!!
void OutPut(LinkList head){
LinkList p;
p = head->next;
while(p){
printf("%s %d %d\n",p->name,p->number,p->score);
p = p->next;
}
}
排序:原有知识的再运用
其实就是原有的数组的排序方法(原谅小编最擅长简单粗暴的冒泡排序),在链表中使用,如有改变,修改指针指向便可,麻烦的就是寻找前后结点
这里以升序演示,降序就是大小换换位置而已
void paixuS(LinkList head){
LinkList p ,s;
int cnt = jishu(head);
for(int i=0;i<cnt;i++){
LinkList z = head;
p = z->next;
//找到对比项前一项
//p是对比项,s是下一项,z是上一项
while(p&&p->next){
s = p->next;
if(p->score>s->score){
z->next = p->next;
p->next = s->next;
s->next = p;
}//大的项往后排
z = z->next;//顺位后移
p = z->next;
}
}
printf("排序后结果如下:\n");
}
第一版:
没有联系文件打印,只是使用链表
主要实现的功能是
************************************************************
1) 输入学生成绩
2) 删除学生信息
3) 修改学生信息
4) 查找学生信息
5) 显示数据
6) 按升序排列学生信息
7) 按降序排序学生信息
8)从文件中读取数据存入链表
0) 退出
***********************************************************
代码如下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct student
{
char name[30];
int number;
int score;
struct student *next;
}STD,*LinkList;
void OutPut(LinkList head);
LinkList chu();
void CreateByHead(LinkList head);
void Out(LinkList head);
STD *search(LinkList head,char name[]);
void change(LinkList head,char name[]);
void Delete(LinkList head,int i);
int jishu(LinkList head);
void menu();
void paixuS(LinkList head);
void paixuJ(LinkList head);
int main()
{
menu();
LinkList ha;
ha = chu();
int a;
scanf("%d",&a);
while(1){
if(a==1){
CreateByHead(ha);
}else if(a==2){
printf("请输入需要修删除第几个学生信息\n");
int k;
scanf("%d",&k);
Delete(ha,k);
}else if(a==3){
printf("请输入需要修改信息的学生姓名\n");
char name[30];
scanf("%s",name);
change(ha,name);
}else if(a==4){
printf("请输入查找学生的姓名\n");
char name[30];
scanf("%s",name);
STD *m = search(ha,name);
printf("%s %d %d\n",m->name,m->number,m->score);
}else if(a==0){
break;
}else if(a==5){
OutPut(ha);
}else if(a==6){
paixuS(ha);
OutPut(ha);
//成绩升序排列
}else if(a==7){
paixuJ(ha);
OutPut(ha);
}
scanf("%d",&a);
}
int cnt;
cnt = jishu(ha);
STD std[100];
LinkList p = ha->next;
for(int i=0;i<cnt;i++){
std[i].number = p->number;
std[i].score = p->score;
strcpy(std[i].name,p->name);
p = p->next;
}
FILE *fp;
fp = fopen("c:\\text\\lian.txt","wb");
if(fp==NULL){
printf("文件打开失败\n");
return 0;
}else {
for(int i=0;i<cnt;i++){
printf("%s %d %d\n",std[i].name,std[i].number,std[i].score);
fprintf(fp,"%s %d %d\n",std[i].name,std[i].number,std[i].score);
}
}
fclose(fp);
return 0;
}
LinkList chu()
{
LinkList head;
head = (STD*)malloc(sizeof(STD));
head -> next = NULL;
return head;
}
void CreateByHead(LinkList head)
{
LinkList s;
char name[30];
int number;
int score;
printf("请输入学生姓名、学号、成绩\n");
while(1)
{
scanf("%s%d%d",name,&number,&score);
if(number==0){
printf("结束输入\n");
break;
}
s = (STD*)malloc(sizeof(STD));
strcpy(s->name,name);
s->number = number;
s->score = score;
s->next = head->next;
head->next = s;
}
}
void Out(LinkList head){
LinkList p;
p = head->next;
printf("学生成绩如下\n");
while(p)
{
printf("%d %s %d\n",p->number,p->name,p->score);
p = p->next;
}
}
STD *search(LinkList head,char name[]){
LinkList s;
s = head->next;
while(s)
{
if(strcmp(s->name,name)!=0) s= s->next;
else break;
}
if(s == NULL) printf("没有找到");
return s;
}
void change(LinkList head,char name[]){
LinkList p;
p = head->next;
while(p)
{
if(strcmp(p->name,name)!=0) p = p->next;
else break;
}
if(p==NULL){
printf("查无此人,操作失败\n");
}else {
printf("输入修改后的学生姓名、学号、成绩\n");
scanf("%s%d%d",p->name,&p->number,&p->score);
}
}
void Delete(LinkList head,int i){
LinkList p=head,s;
int j=0;
while(p&&j<i-1){
p = p->next;
j++;
}
if(p==NULL||p->next==NULL){
printf("ERROR\n");
}else{
s = p->next;
p->next = s->next;
free(s);
}
}
int jishu(LinkList head){
int cnt = 0;
LinkList p;
p = head->next;
while(p){
cnt++;
p = p->next;
}
return cnt;
}
void menu(){
printf("***********学生信息管理系统**************\n");
printf("1) 输入学生成绩\n2) 删除学生信息\n3) 修改学生信息\n4) 查找学生信息\n5) 显示\n6) 按升序排列学生信息\n7) 按降序排序学生信息\n0) 退出\n");
}
void OutPut(LinkList head){
LinkList p;
p = head->next;
while(p){
printf("%s %d %d\n",p->name,p->number,p->score);
p = p->next;
}
}
void paixuS(LinkList head){
LinkList p ,s;
int cnt = jishu(head);
for(int i=0;i<cnt;i++){
LinkList z = head;
p = z->next;
//找到对比项前一项
//p是对比项,s是下一项,z是上一项
while(p&&p->next){
s = p->next;
if(p->score>s->score){
z->next = p->next;
p->next = s->next;
s->next = p;
}//大的项往后排
z = z->next;//顺位后移
p = z->next;
}
}
printf("排序后结果如下:\n");
}
void paixuJ(LinkList head){
LinkList p ,s;
int cnt = jishu(head);
for(int i=0;i<cnt;i++){
LinkList z = head;
p = z->next;
while(p&&p->next){
s = p->next;
if(p->score<s->score){
z->next = p->next;
p->next = s->next;
s->next = p;
}
z = z->next;
p = z->next;
}
}
printf("排序后结果如下:\n");
}
对于删除功能的优化
对于查找第几个学生,这种操作属实鸡肋,因此优化为按照姓名查找
主要思路:
输入姓名后,使用strcmp()函数进行比较,寻找。
如果当指向空指针,则没有找到,输出 “ 查无此人 ”。
代码如下(简短代码)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct student{
char name[30];
int score;
struct student *next;
}STD,*LinkList;
LinkList chu();
void CreateByHear(LinkList head);
void OutPut(LinkList head);
STD *Search(LinkList head,char name[]);
void Delete(LinkList head,char name[]);
int main()
{
LinkList ha;
ha = chu();
CreateByHear(ha);
OutPut(ha);
printf("ÇëÊäÈëÐÕÃû\n");
char na[30];
scanf("%s",na);
// LinkList p = Search(ha,na);
// printf("%s %d",p->name,p->score);
//查找
Delete(ha,na);
OutPut(ha);
}
LinkList chu(){
LinkList head;
head = (STD*)malloc(sizeof(STD));
head ->next = NULL;
return head;
}
void CreateByHear(LinkList head){
//尾插法创建链表
LinkList p,s;
p = head;
char name[30];
int score;
printf("请输入学生信息\n");
while(1)
{
scanf("%s %d",name,&score);
if(score==0){
break;
}
s = (STD*)malloc(sizeof(STD));//动态分配内存
strcpy(s->name,name);
s->score = score;
p->next = s;
p = s;
}
p->next = NULL;
}
void OutPut(LinkList head){
LinkList p = head->next;
while(p){
printf("%s %d\n",p->name,p->score);
p = p->next;
}
}
STD* Search(LinkList head,char name[]){
LinkList p;
p = head->next;
while(p){
if(strcmp(p->name,name)!=0){
p = p->next;
}else break;
}
if(p==NULL) printf("查无此人\n");
return p;
}
void Delete(LinkList head,char name[]){
LinkList p,r;
r = head;
p = r->next;
//p是下一个结点
while(r->next){
if(strcmp(p->name,name)!=0){
r = r->next;
p = r->next;
}else {
r->next = p->next;
free(p);
break;
}
}
if(p==NULL) printf("查无此人\n");
}
第二版
由于第一版使用链表输出内容没有办法储存,因此使用文件,选择将链表内存储的数据,打印到txt文件里,便于整理数据,提高实用性。
同时添加了把文件的数据传入链表中进行操作的功能,进一步增强实用性
***********************实用主义万岁!!!!!!!*********************
与文件联合
代码如下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct student
{
char name[30];
int number;
int score;
struct student *next;
}STD,*LinkList;
void OutPut(LinkList head);
LinkList chu();
void CreateByHead(LinkList head);
void Out(LinkList head);
STD *search(LinkList head,char name[]);
void change(LinkList head,char name[]);
void Delete(LinkList head,int i);
int jishu(LinkList head);
void menu();
void paixuS(LinkList head);
void paixuJ(LinkList head);
void Daoru(LinkList head);
void Cun(LinkList head,STD std[],int n);
int main()
{
menu();
LinkList ha;
ha = chu();
int a;
scanf("%d",&a);
while(1){
if(a==1){
CreateByHead(ha);
}else if(a==2){
printf("请输入需要修删除第几个学生信息\n");
int k;
scanf("%d",&k);
Delete(ha,k);
}else if(a==3){
printf("请输入需要修改信息的学生姓名\n");
char name[30];
scanf("%s",name);
change(ha,name);
}else if(a==4){
printf("请输入查找学生的姓名\n");
char name[30];
scanf("%s",name);
STD *m = search(ha,name);
printf("%s %d %d\n",m->name,m->number,m->score);
}else if(a==0){
break;
}else if(a==5){
OutPut(ha);
}else if(a==6){
paixuS(ha);
OutPut(ha);
//成绩升序排列
}else if(a==7){
paixuJ(ha);
OutPut(ha);
}else if(a==8){
Daoru(ha);
}
scanf("%d",&a);
}
int cnt;
cnt = jishu(ha);
STD std[100];
LinkList p = ha->next;
for(int i=0;i<cnt;i++){
std[i].number = p->number;
std[i].score = p->score;
strcpy(std[i].name,p->name);
p = p->next;
}
FILE *fp;
fp = fopen("c:\\text\\lian.txt","wb");
if(fp==NULL){
printf("文件打开失败\n");
return 0;
}else {
for(int i=0;i<cnt;i++){
printf("%s %d %d\n",std[i].name,std[i].number,std[i].score);
fprintf(fp,"%s %d %d\n",std[i].name,std[i].number,std[i].score);
}
}
fclose(fp);
return 0;
}
LinkList chu()
{
LinkList head;
head = (STD*)malloc(sizeof(STD));
head -> next = NULL;
return head;
}
void CreateByHead(LinkList head)
{
LinkList s;
char name[30];
int number;
int score;
printf("请输入学生姓名、学号、成绩\n");
while(1)
{
scanf("%s%d%d",name,&number,&score);
if(number==0){
printf("结束输入\n");
break;
}
s = (STD*)malloc(sizeof(STD));
strcpy(s->name,name);
s->number = number;
s->score = score;
s->next = head->next;
head->next = s;
}
}
void Out(LinkList head){
LinkList p;
p = head->next;
printf("学生成绩如下\n");
while(p)
{
printf("%d %s %d\n",p->number,p->name,p->score);
p = p->next;
}
}
STD *search(LinkList head,char name[]){
LinkList s;
s = head->next;
while(s)
{
if(strcmp(s->name,name)!=0) s= s->next;
else break;
}
if(s == NULL) printf("没有找到");
return s;
}
void change(LinkList head,char name[]){
LinkList p;
p = head->next;
while(p)
{
if(strcmp(p->name,name)!=0) p = p->next;
else break;
}
if(p==NULL){
printf("查无此人,操作失败\n");
}else {
printf("输入修改后的学生姓名、学号、成绩\n");
scanf("%s%d%d",p->name,&p->number,&p->score);
}
}
void Delete(LinkList head,int i){
LinkList p=head,s;
int j=0;
while(p&&j<i-1){
p = p->next;
j++;
}
if(p==NULL||p->next==NULL){
printf("ERROR\n");
}else{
s = p->next;
p->next = s->next;
free(s);
}
}
int jishu(LinkList head){
int cnt = 0;
LinkList p;
p = head->next;
while(p){
cnt++;
p = p->next;
}
return cnt;
}
void menu(){
printf("***********学生信息管理系统**************\n");
printf("1) 输入学生成绩\n2) 删除学生信息\n3) 修改学生信息\n4) 查找学生信息\n5) 显示\n6) 按升序排列学生信息\n7) 按降序排序学生信息\n8)从文件中读取数据存入链表\n0) 退出\n");
}
void OutPut(LinkList head){
LinkList p;
p = head->next;
while(p){
printf("%s %d %d\n",p->name,p->number,p->score);
p = p->next;
}
}
void paixuS(LinkList head){
LinkList p ,s;
int cnt = jishu(head);
for(int i=0;i<cnt;i++){
LinkList z = head;
p = z->next;
//找到对比项前一项
//p是对比项,s是下一项,z是上一项
while(p&&p->next){
s = p->next;
if(p->score>s->score){
z->next = p->next;
p->next = s->next;
s->next = p;
}//大的项往后排
z = z->next;//顺位后移
p = z->next;
}
}
printf("排序后结果如下:\n");
}
void paixuJ(LinkList head){
LinkList p ,s;
int cnt = jishu(head);
for(int i=0;i<cnt;i++){
LinkList z = head;
p = z->next;
while(p&&p->next){
s = p->next;
if(p->score<s->score){
z->next = p->next;
p->next = s->next;
s->next = p;
}
z = z->next;
p = z->next;
}
}
printf("排序后结果如下:\n");
}
void Cun(LinkList head,STD std[],int n)
{
LinkList s,p = head;
for(int i=0;i<n;i++){
s = (STD*)malloc(sizeof(STD));
strcpy(s->name,std[i].name);
s->number = std[i].number;
s->score = std[i].score;
p->next = s;
p = s;
}
p->next = NULL;
}
void Daoru(LinkList head)
{
STD std[1000];
FILE *fp;
int n;
printf("请输入学生数量:\n");
scanf("%d",&n);
fp = fopen("c:\\text\\lian.txt","r");
for(int i=0;i<n;i++){
fscanf(fp,"%s %d %d",std[i].name,&std[i].number,&std[i].score);
}
Cun(head,std,n);
OutPut(head);
fclose(fp);//关闭文件
}
一些想法
目前来看该简易系统基本可以完成一些简易操作,譬如链表的增、删、改、查
目前来看,系统内存储的数据只有学生姓名,序号,以及总成绩。
太过稀少,可以增加为 学生姓名,序号,语文,数学,英语,以及总成绩。
总成绩是语数英三科成绩总和,同时,储存文件时排序按照总成绩升降排序。
(单纯只是觉得这样排序的话实用性更好一点,毕竟实用万岁!L('ω')┘三└('ω')」)