前言:今天花了一下午时间学习了链表,讲自己所学内容分享给大家,本篇内容对于链表的使用进行了非常详细的讲解,搭配代码的编写事半功倍,希望对大家有所帮助,喜欢的可以一键三连(点赞,收藏,评论)
线性表
含义:当一组数据元素形成了前后关系时,我们称之为线性表
线性表在内存中的两种形式:
顺序表:以数组的形式存放,元素在内存中是连续存放的
特点:插入或删除一个数据元素时,需要移动其他数据元素
(线性)链表:数据元素在内存中不需要连续存放,而是通过指针将个数据单元链接起来,就像一条”链子“一样将数据单元前后元素链接起来
特点:插入或删除一个数据元素时,不需要移动其他数据元素
(线性)链表
线性链表如何定义?
线性链表的节点可以用一个结构体类型来定义,其形式为
struct 结构体类型名
{
数据成员定义;
struct 节点结构体类型名 *指针变量名;
};
例子:
struct GRADE_iInfo
{
int score;
struct GRADE_iInfo *next;
};
typedef struct GRADE_iInfo NODE;//类型重命名
链表的节点
节点包括:数据域和指针域
数据域:存放本节点的数据
指针域:存放下一节点的地址
头节点指针:存放第一个节点的指针(在下面创建链表中有详细图解)
线性链表的基本操作
基本操作有:创建,插入,删除,输出,销毁
以题目为例:
建立一个学生成绩的线性链表,然后对其进行插入,删除,显示,最后销毁该链表
1、主函数:
#include<stdio.h>
#include<stdlib.h>//动态内存函数的头文件
//创建结构体类型,因为节点可以用结构体类型来定义
struct Grade_Info
{
int score;
struct Grade_Info *next;//节点的基类型要和节点的类型一致,相当于结构体的自引用
};
typedef struct Grade_Info NODE;//类型重命名
//函数声明
NODE*Creat_LinkList();//创建链表
void Insert_LinkList(NODE*head,NODE*pnew,int i);//插入节点
void Delete_LinkList(NODE*head,int i);//删除节点
void Display_Linklist(NODE*head);//输出链表
void Free_LinkList(NODE*head);//销毁链表
int main()
{
NODE*head = NULL;//头节点
NODE*pnew = NULL;//存放新节点的地址
head = Creat_LinkList();//创建链表
if(head == NULL)//创建失败
return 0 ;
printf("after creat:");
Display_Linklist(head);//输出链表的值
//新建一个要插入的节点
pnew = (NODE*)malloc(sizeof(NODE));//动态内存开辟
if(pnew == NULL)//新节点创建失败,则返回
{
printf("no enough memory\n");
return 0;
}
pnew->score = 88;
//将新节点插入节点2的后面
Insert_LinkList(head,pnew,2);
return 0;
}
2、创建线性链表
含义:从无到有创建一个链表,即往空链表中依次插入若干个节点,并保持节点之间的前驱和 后继关系
基本思想:首先创建一个头节点,让头指针(head)和尾指针(tail)都指向该节点,并设置该节点的指针域为NULL(链尾标志);然后为实际数据创建一个节点,用指针pnew(用来存放新节点的地址)指向它,并将实际数据放在该节点的数据域,其指针与为NULL;最后将该节点插入到tail所指向节点的后面,同时时tail指向pnew指向的节点
![](https://img-blog.csdnimg.cn/img_convert/d9b1d4e0417250d84823799a1862144b.jpeg)
NODE*Creat_LinkList()
{
NODE*head = NULL;//头节点
NODE*tail = NULL;//尾节点
NODE*pnew = NULL;//存放新节点的地址
int score = 0;
head = (NODE*)malloc(sizeof(NODE));//创建头节点
if(head==NULL)
{
printf("no enough memory!\n");
return NULL;
}
head->next = NULL;
tail = head;
printf("intput the score of students:\n");
while(1)//创建学生成绩线性链表
{
scanf("%d",&score);//输入成绩
if(score<0)//成绩为负,循环退出
{
break;
}
//创建一个新的节点,存放成绩
pnew = (NODE*)malloc(sizeof(NODE));
if(pnew == NULL)
{
printf("no enough memory!\n");
return NULL;
}
pnew->score = score;
pnew->next = NULL;
tail->next = pnew;
tail = pnew;
}
return head;
}
3、插入节点
基本思想:通过单链表的头指针head,首先找到链表的第一个节点;然后顺着节点的指针域找到第i个节点,最后将pnew指向的新节点插入到第i个节点之后。插入时首先将新节点的指针域指向第i个节点的后继节点,然后再将第i个节点的指针域指向新节点。注意顺序不能颠倒。当i=0时;表示头节点
void Insert_LinkList(NODE*head,NODE*pnew,int i)
{
//i == 2
NODE*p = NULL;
int j = 0;
p = head;
for(j = 0;j<i&&p!=NULL;j++)//将p指向要插入的第i个节点
{
p = p->next;
}
if(p == NULL)//表明链表中的第i个节点不存在
{
printf("the %d nonde not found\n",i);
return;
}
pnew->next = p->next;;//将插入节点的指针域指向第i个节点后继节点
p->next=pnew;//将第i个节点的指针域指插入的节点
}
4、删除节点
void Delete_LinkList(NODE*head,int i)
{
NODE*p = NULL;
NODE*q = NULL;
int j = 0;
if(i == 0)//删除的是头指针
{
return ;
}
p = head;
//将p指向要删除的第i个节点的前驱节点
for(j = 1;j<i&&p->next!=NULL;j++)
{
p = p->next;
}
if(p->next == NULL)//表明要删除的第i个节点不存在
{
printf("the %d node not found\n",i);
return;
}
q = p->next;//q指向待删除的节点i
p->next = q->next;//删除节点i
free(q);//释放节点的内存单元
}
5、输出线性链表
void Display_Linklist(NODE*head)
{
NODE*p = NULL;
for(p = head->next;p!=NULL;p = p->next)//注意区分节点的地址和节点的指针域
{
printf("%d ",p->score);
}
printf("\n");
}
6、销毁线性链表
基本思想:每次删除头节点的后继节点,最后删除头节点。注意,不是删除了头节点就可以删除震整个链表,要知道链表是一个节点一个接待你建立起来的,所以销毁它也必须一个节点一个节点的删除才行
void Free_LinkList(NODE*head)
{
NODE*p = NULL;
NODE*q = NULL;
p = head;
while(p->next != NULL)
{
q = p->next;
p->next = q->next;
free(q);
}
free(head);
}
7、总代码:
#include<stdio.h>
#include<stdlib.h>//动态内存函数的头文件
//创建结构体类型,因为节点可以用结构体类型来定义
enum choice
{
no,//0
yes//1
};
struct Grade_Info
{
int score;
struct Grade_Info* next;//节点的基类型要和节点的类型一致,相当于结构体的自引用
};
typedef struct Grade_Info NODE;//类型重命名
//函数声明
NODE* Creat_LinkList();//创建链表
void Insert_LinkList(NODE* head, NODE* pnew, int i);//插入节点
void Delete_LinkList(NODE* head, int i);//删除节点
void Display_Linklist(NODE* head);//输出链表
void Free_LinkList(NODE* head);//销毁链表
int main()
{
NODE* head = NULL;//头节点
NODE* pnew = NULL;//存放新节点的地址
head = Creat_LinkList();//创建链表
if (head == NULL)//创建失败
return 0;
printf("after creat:");
Display_Linklist(head);//输出链表的值
printf("是否要插入一个学生的成绩?是:1,否:0\n");
int n = 0;
scanf("%d", &n);
switch (n)
{
case no:
break;
case yes:
{
int i = 0;
printf("要插入到第几个学生后?\n");
scanf("%d", &i);
//新建一个要插入的节点
pnew = (NODE*)malloc(sizeof(NODE));//动态内存开辟
if (pnew == NULL)//新节点创建失败,则返回
{
printf("no enough memory\n");
return 0;
}
int score = 0;
printf("输入插入学生的成绩:");
scanf("%d", &score);
pnew->score = score;
Insert_LinkList(head, pnew,i );//将新节点插入节点n的后面
printf("afte insert:");
Display_Linklist(head);//输出链表的值
}
}
printf("要删除某个学生的成绩吗?是:1,否:0\n");
int m = 0;
scanf("%d", &m);
switch (m)
{
case no:
break;
case yes:
{
int i = 0;
printf("要删除第几个学生的成绩?请输入:");
scanf("%d", &i);
Delete_LinkList(head,i);
printf("after Delete:");
Display_Linklist(head);//输出链表的值
}
}
//没有以上操作就销毁链表
Free_LinkList(head);
return 0;
}
//创建链表
NODE* Creat_LinkList()
{
NODE* head = NULL;//头节点
NODE* tail = NULL;//尾节点
NODE* pnew = NULL;//存放新节点的地址
int score = 0;
head = (NODE*)malloc(sizeof(NODE));//创建头节点
if (head == NULL)
{
printf("no enough memory!\n");
return NULL;
}
head->next = NULL;
tail = head;
printf("intput the score of students:\n");
while (1)//创建学生成绩线性链表
{
scanf("%d", &score);//输入成绩
if (score < 0)//成绩为负,循环退出
{
break;
}
//创建一个新的节点,存放成绩
pnew = (NODE*)malloc(sizeof(NODE));
if (pnew == NULL)
{
printf("no enough memory!\n");
return NULL;
}
pnew->score = score;
pnew->next = NULL;
tail->next = pnew;
tail = pnew;
}
return head;
}
//插入节点
void Insert_LinkList(NODE* head, NODE* pnew,int i)
{
//i == 2
NODE* p = NULL;
int j = 0;
p = head;
for (j = 0; j < i && p != NULL; j++)//将p指向要插入的第i个节点
{
p = p->next;
}
if (p == NULL)//表明链表中的第i个节点不存在
{
printf("the %d nonde not found\n", i);
return;
}
pnew->next = p->next;;//将插入节点的指针域指向第i个节点后继节点
p->next = pnew;//将第i个节点的指针域指插入的节点
}
//删除节点
void Delete_LinkList(NODE* head, int i)
{
NODE* p = NULL;
NODE* q = NULL;
int j = 0;
if (i == 0)//删除的是头指针
{
return;
}
p = head;
//将p指向要删除的第i个节点的前驱节点
for (j = 1; j < i && p->next != NULL; j++)
{
p = p->next;
}
if (p->next == NULL)//表明要删除的第i个节点不存在
{
printf("the %d node not found\n", i);
return;
}
q = p->next;//q指向待删除的节点i
p->next = q->next;//删除节点i
free(q);//释放节点的内存单元
}
//输出链表
void Display_Linklist(NODE* head)
{
NODE* p = NULL;
for (p = head->next; p != NULL; p = p->next)//注意区分节点的地址和节点的指针域
{
printf("%d ", p->score);
}
printf("\n");
}
//销毁链表
void Free_LinkList(NODE* head)
{
NODE* p = NULL;
NODE* q = NULL;
p = head;
while (p->next != NULL)
{
q = p->next;
p->next = q->next;
free(q);
}
free(head);
}