定义:链表是一种物理存储上非连续,数据元素的逻辑顺序通过链表中的指针链接次序,实现的一种线性存储结构。
特点:链表由一系列节点(链表中每一个元素称为节点)组成,节点在运行时动态生成(malloc),每个节点包括两个部分:
- 一个是存储数据元素的数据域
- 另一个是存储下一个节点地址的指针域
链表的操作:增、删、改、查
链表的创建、链表的遍历、链表的释放
#include <stdio.h>
#include <stdlib.h>
// 定义节点结构体
typedef struct student
{
// 数据域
int num; // 学号
int score; // 分数
char name[20]; // 姓名
// 指针域
struct student *next;
}STU;
void link_creat_head(STU **p_head, STU *p_new)
{
STU *p_mov = *p_head;
if(*p_head == NULL) // 当第一次加入链表为空时,head执行p_new
{
*p_head = p_new;
p_new->next=NULL;
}
else // 第二次及以后加入链表
{
while (p_mov->next != NULL) {
p_mov = p_mov->next; // 找到原有链表的最后一个节点
}
p_mov->next = p_new; // 将新申请的节点加入链表
p_new->next = NULL;
}
}
// 链表的遍历
void link_print(STU *head)
{
STU *p_mov; // 定义新的指针 用来保存链表的首地址
p_mov = head;
while (p_mov != NULL) // 当指针保存最后一个结点的指针域是NULL时,循环结束。
{
printf("num=%d score=%d name:%s\n", p_mov->num, p_mov->score, p_mov->name);
p_mov = p_mov->next; // 注意千万不要使用p_mov++ 因为当前链表不一定是连续的内存地址
}
}
// 链表的释放
void link_free(STU **p_head)
{
STU *pb = *p_head; // 定义一个指针变量保存头结点的地址
while (*p_head != NULL)
{
// 先保存p_head指向的节点的地址
pb = *p_head;
// p_head保存下一个节点的地址
*p_head = (*p_head)->next;
// 释放结点并防止野指针
free(pb);
pb = NULL;
}
}
int main()
{
STU *head = NULL, *p_new = NULL;
int num,i;
printf("input init number:\n");
scanf("%d", &num);
for(i = 0; i<num; i++)
{
p_new = (STU*)malloc(sizeof(STU)); // 申请一个新节点
printf("input num/score/name:\n"); // 给新节点赋值
scanf("%d %d %s", &p_new->num, &p_new->score, &p_new->name);
link_creat_head(&head, p_new); // 将新节点加入链表
// &head 是一级指针的地址(二级指针)
}
link_print(head);
link_free(&head);
return 0;
}
也可参考这个链接
/*尾插法建立链表*/
#include <stdio.h>
#include <stdlib.h>
struct list //创建链表的结构体
{
int data; //创建数据域
struct list *next; //创建指针域
};
int main(int argc,char *argv[])
{
int n; //设置结点的个数
int i; //设置创建的结点的个数
struct list *head = (struct list *)malloc(sizeof(struct list));
//创建头结点用malloc分配内存
head->next = NULL; //头结点指针初始化
struct list *p; //创建p结点,p结点用于记录链表尾结点
p = head; //p结点指针赋值为头结点
printf("input init number:\n");
scanf("%d",&n);
/* 链表的创建*/
for(i=0;i<n;i++) //循环创建结点
{
struct list *p1=(struct list *)malloc(sizeof(struct list));
//创建p1结点,并分配内存
scanf("%d",&p1->data); //给p1结点赋值
p->next = p1;
p1->next = NULL; //让插在尾部的p1结点的指针指向NULL
p = p1;
}
/*链表的遍历*/
p = head; //从头结点开始遍历
while(p->next != NULL) //只要p结点下一个结点不为空,证明还有结点存在,打印p后面结点的数据
{
printf("%d",p->next->data);
p = p->next; //p结点移动到下一个结点
}
printf("\n");
/*清空链表*/
p=head->next; //让p结点指向头结点下一位
while(head->next!=NULL) //当头结点下一位一直不为空时
{
head->next=p; //将头结点下一位赋予p
p=p->next; //新的p结点=头结点下一位的下一位 直到尾结点=头结点
free(head->next);
head->next=NULL; //确保头结点下一位为空
}
printf("clean the list sucessfuly!\n");
return 0;
}
链表节点的查找
#include <stdio.h>
#include <stdlib.h>
// 定义节点结构体
typedef struct student
{
// 数据域
int num; // 学号
int score; // 分数
char name[20]; // 姓名
// 指针域
struct student *next;
}STU;
void link_creat_head(STU **p_head, STU *p_new)
{
STU *p_mov = *p_head;
if(*p_head == NULL) // 当第一次加入链表为空时,head执行p_new
{
*p_head = p_new;
p_new->next=NULL;
}
else // 第二次及以后加入链表
{
while (p_mov->next != NULL) {
p_mov = p_mov->next; // 找到原有链表的最后一个节点
}
p_mov->next = p_new; // 将新申请的节点加入链表
p_new->next = NULL;
}
}
// 链表的遍历
void link_print(STU *head)
{
STU *p_mov; // 定义新的指针 用来保存链表的首地址
p_mov = head;
while (p_mov != NULL) // 当指针保存最后一个结点的指针域是NULL时,循环结束。
{
printf("num=%d score=%d name:%s\n", p_mov->num, p_mov->score, p_mov->name);
p_mov = p_mov->next; // 注意千万不要使用p_mov++ 因为当前链表不一定是连续的内存地址
}
}
// 链表的释放
void link_free(STU **p_head)
{
STU *pb = *p_head; // 定义一个指针变量保存头结点的地址
while (*p_head != NULL)
{
// 先保存p_head指向的节点的地址
pb = *p_head;
// p_head保存下一个节点的地址
*p_head = (*p_head)->next;
// 释放结点并防止野指针
free(pb);
pb = NULL;
}
}
// 链表节点的查找
// 按照学号查找
STU * link_search_num(STU *head,int num)
{
STU *p_mov; // 定义的指针变量保存第一个结点的地址
p_mov = head;
while (p_mov != NULL) // 当没有到达最后一个结点的指针域时循环继续
{
// 如果找到是当前结点的数据,则返回当前结点的地址
if(p_mov->num == num) // 找到了
{
return p_mov;
}
// 如果没有找到,则继续对比下一个结点的指针域
p_mov = p_mov->next;
}
// 当循环结束的时候还没有找到,说明要查找的数据不存在,返回NULL进行标识
return NULL; // 没有找到
}
// 按照姓名查找
STU * link_search_name(STU *head,char *name)
{
STU *p_mov;
p_mov = head;
while (p_mov != NULL)
{
if(strcmp(p_mov->name,name) == 0) // 找到了 strcmp函数比较两个字符串的内容是否一致
{
return p_mov;
}
p_mov = p_mov->next;
}
return NULL; // 没有找到
}
int main()
{
STU *head = NULL, *p_new = NULL;
int num,i;
printf("input init number:\n");
scanf("%d", &num);
for(i = 0; i<num; i++)
{
p_new = (STU*)malloc(sizeof(STU)); // 申请一个新节点
printf("input num/score/name:\n"); // 给新节点赋值
scanf("%d %d %s", &p_new->num, &p_new->score, &p_new->name);
link_creat_head(&head, p_new); // 将新节点加入链表
// &head 是一级指针的地址(二级指针)
}
link_print(head);
// 查学号
#if 0
STU *pb;
while (1)
{
printf("input num:\n");
scanf("%d",&num);
pb = link_search_num(head,num);
if(pb!=NULL)
{
printf("found!!!\n");
}
else
{
printf("not found\n");
}
}
#endif
#if 1
STU *pb;
char name[32] = "";
while (1)
{
printf("input name:\n");
scanf("%s",name);
pb = link_search_name(head,name);
if(pb!=NULL)
{
printf("found!!!\n");
}
else
{
printf("not found\n");
}
}
#endif
link_free(&head);
return 0;
}
链表节点的删除、链表中插入一个节点
#include <stdio.h>
#include <stdlib.h>
// 定义节点结构体
typedef struct student
{
// 数据域
int num; // 学号
int score; // 分数
char name[20]; // 姓名
// 指针域
struct student *next;
}STU;
void link_creat_head(STU **p_head, STU *p_new)
{
STU *p_mov = *p_head;
if(*p_head == NULL) // 当第一次加入链表为空时,head执行p_new
{
*p_head = p_new;
p_new->next=NULL;
}
else // 第二次及以后加入链表
{
while (p_mov->next != NULL) {
p_mov = p_mov->next; // 找到原有链表的最后一个节点
}
p_mov->next = p_new; // 将新申请的节点加入链表
p_new->next = NULL;
}
}
// 链表的遍历
void link_print(STU *head)
{
STU *p_mov; // 定义新的指针 用来保存链表的首地址
p_mov = head;
while (p_mov != NULL) // 当指针保存最后一个结点的指针域是NULL时,循环结束。
{
printf("num=%d score=%d name:%s\n", p_mov->num, p_mov->score, p_mov->name);
p_mov = p_mov->next; // 注意千万不要使用p_mov++ 因为当前链表不一定是连续的内存地址
}
}
// 链表的释放
void link_free(STU **p_head)
{
STU *pb = *p_head; // 定义一个指针变量保存头结点的地址
while (*p_head != NULL)
{
// 先保存p_head指向的节点的地址
pb = *p_head;
// p_head保存下一个节点的地址
*p_head = (*p_head)->next;
// 释放结点并防止野指针
free(pb);
pb = NULL;
}
}
// 链表节点的查找
// 按照学号查找
STU * link_search_num(STU *head,int num)
{
STU *p_mov; // 定义的指针变量保存第一个结点的地址
p_mov = head;
while (p_mov != NULL) // 当没有到达最后一个结点的指针域时循环继续
{
// 如果找到是当前结点的数据,则返回当前结点的地址
if(p_mov->num == num) // 找到了
{
return p_mov;
}
// 如果没有找到,则继续对比下一个结点的指针域
p_mov = p_mov->next;
}
// 当循环结束的时候还没有找到,说明要查找的数据不存在,返回NULL进行标识
return NULL; // 没有找到
}
// 按照姓名查找
STU * link_search_name(STU *head,char *name)
{
STU *p_mov;
p_mov = head;
while (p_mov != NULL)
{
if(strcmp(p_mov->name,name) == 0) // 找到了 strcmp函数比较两个字符串的内容是否一致
{
return p_mov;
}
p_mov = p_mov->next;
}
return NULL; // 没有找到
}
// 链表结点的删除
void link_delete_num(STU **p_head, int num)
{
STU *pb, *pf;
pb = pf = *p_head;
if(*p_head == NULL) // 链表为空,不用删
{
printf("null ,no need to del");
return ;
}
while (pb->num != num && pb->next != NULL) // 循环找,要删除的结点
{
pf = pb;
pb = pb->next;
}
if (pb->num == num) // 找到了一个节点的num和num相同
{
if(pb == *p_head) // 要删除的节点是头节点
{
*p_head = pb->next; // 让保存头结点的指针,保存后一个结点的地址。
}
else
{
pf->next = pb->next; // 前一个节点的指针域,保存要删除的,后一个结点的地址。
}
// 释放空间
free(pb);
pb = NULL;
}
else // 没有找到
{
printf("not found...\n");
}
}
// 链表的插入:按照学号的顺序插入
void link_insert_num(STU **p_head,STU *p_new)
{
STU *pb, *pf;
pb = pf = *p_head;
if(*p_head == NULL) // 链表为空链表
{
*p_head = p_new;
p_new->next = NULL;
return ;
}
while ( ( p_new->num >= pb->num ) && ( pb->next != NULL ) )
{
pf = pb;
pb = pb->next;
}
if(p_new->num < pb->num) // 找到一个节点的num比新来的节点num大
{
if(pb == *p_head) // 找到的节点是头节点,插在最前面
{
p_new->next = *p_head;
*p_head = p_new;
}
else
{
pf->next = p_new;
p_new->next = pb;
}
}
else // 没有找到pb的num比p_new->num大的节点,插在最后
{
pb->next = p_new;
p_new->next = NULL;
}
}
int main()
{
STU *head = NULL, *p_new = NULL;
int num,i;
printf("input init number:\n");
scanf("%d", &num);
for(i = 0; i<num; i++)
{
p_new = (STU*)malloc(sizeof(STU)); // 申请一个新节点
printf("input num/score/name:\n"); // 给新节点赋值
scanf("%d %d %s", &p_new->num, &p_new->score, &p_new->name);
link_creat_head(&head, p_new); // 将新节点加入链表
// &head 是一级指针的地址(二级指针)
}
link_print(head);
// 删除操作
// printf("delete: input num:\n");
// scanf("%d", &num);
// link_delete_num(&head, num);
// link_print(head);
// 链表中插入一个节点
while (1)
{
printf("Please enter the content(num score name) you want to insert\n");
p_new = (STU*)malloc(sizeof(STU)); // 申请一个新节点
scanf("%d %d %s", &p_new->num, &p_new->score, &p_new->name);
link_insert_num(&head, p_new);
link_print(head);
}
// 查学号
#if 0
STU *pb;
while (1)
{
printf("input num:\n");
scanf("%d",&num);
pb = link_search_num(head,num);
if(pb!=NULL)
{
printf("found!!!\n");
}
else
{
printf("not found\n");
}
}
#endif
#if 0
STU *pb;
char name[32] = "";
while (1)
{
printf("input name:\n");
scanf("%s",name);
pb = link_search_name(head,name);
if(pb!=NULL)
{
printf("found!!!\n");
}
else
{
printf("not found\n");
}
}
#endif
link_free(&head);
return 0;
}