链表有一系列的节点组成(每个节点一般为结构体形式),节点在运行时动态生成(malloc)
一、单向链表的创建、插入、遍历、查找、排序、逆序、删除、释放
例:typedef struct student{
int num;
float score;
struct student *next;
}STU;
2)链表不为空时,首先遍历链表找到链表的尾节点,然后将待添加的新节点挂在尾节点上
STU *head,*new;
new=(STU *)malloc(sizeof(STU));
void link_create(STU **head,STU *new)
{
//先定义一个中间变量,来保证头文件不变
STU *p_mov=*head;
if(*head==NULL)//插入第一个节点
{
*head=new;
new->next=NULL;
}
else
{
while(p_mov->next!=NULL)//找到尾节点
{
p_mov=p_mov->next;
}
p_mov->next=new;//将新节点添加到尾节点
new->next=NULL;
}
}
添加节点到链表到链表的头部
void link_create(STU **head,STU *new)
{
if(*head==NULL)//插入第一个节点
{
*head=new;
new->next=NULL;
}
else
{
new->next=*head;
*head=new->next;
}
}
获得p_mov所指节点的信息 3)使p_mov指向下一个节点
void link_print(STU *p_head)
{
STU *p_mov;
p_mov=p_head;
while(p_mov!=NULL)
{
printf("num=%d name= %s score=%d\n",p_mov->num,p_mov->name,p_mov->score);
p_mov=p_mov->next;
}
}
获得p_mov所指节点的信息 3)比较是否是要查找的节点
STU *link_search_name(STU *head,char *name)
{
STU *p_mov;
p_mov=p_head;
while(p_mov!=NULL)
{
if(strcmp(p_mov->name,name)==0)
{
return p_mov;
}
else
p_mov=p_mov->next;
}
return NULL;
}
STU * link_free(STU **head)
{
STU *p_mov;
p_mov=*head;
while(*head!=NULL)
{
p_mov=*head;
*head=*head->next;
free(p_mov);
}
return NULL;
}
2)删除的不是第一个节点,使被删除节点的前个节点指向后一个节点
void link_delete_num(STU **p_head,int num)
{
//先定义2个指针,用来保存上一个节点和下一个节点,即该节点的上一节点的next指向该节点的
下一节点
STU *pb,pf;
pb=pf=*p_head;
if(*p_head==NULL)
{
printf("该链表为空,没有要删除的节点\n");
return ;
}
while(pb->num!=num && pb->next!=NULL)
{
pf=pb;
pb=pb->next;
}
if(pb->num==num)
{
if(pb==*p_head)
{
*p_head=pb->next;
}
else
{
pf->next=pb->next;
}
free(pb);
}
else
{
printf("没有您要删除的节点\n");
}
}
void link_insert_num(STU** head,STU* new)
{
STU *pb,*pf;
pb=pf=*head;
if(*head==NULL)
{
*head=new;
new->next=NULL;
}
while((new->num<=pb->num)&&(pb->next)!=NULL)
{
pf=pb;
pb=pb->next;
}
if(new->num >pb->num)
{
if(pb==*head)
{
new->next=*head;
*head=new;
}
else
{
pf->next=new;
new->next=pb;
}
}
else
{
pb->next=new;
new->next=NULL;
}
}
{
STU *pb,*pf,temp;
pb=pf=head;
if(head==NULL)
{
printf("链表为空\n");
return 0;
}
while(pf->next!=NULL)
{
pb=pf->next;
while(pb!=NULL)
{
if(pb->num < pf->num)
{
temp=*pf;
*pf=*pb;
*pb=temp;
temp->next=pf->next;
pf->next=pb->next;
pb->next=pf->next;
}
pb=pb->next;
}
pf=pf->next;
}
}
{
STU *pb,*pf,*r;
pb=pf=head;
if(head==NULL)
{
printf("链表为空\n");
return 0;
}
if(head->next==NULL)
{
printf("链表只有一个节点,不用逆序\n");
return 0;
}
pb=pf->next;
while(pb!=NULL)
{
r = pb->next;
pb->next=pf;
pf=pb;
pb=r;
}
head->next=NULL;
head=pf;
return 0;
}
节点分为两部分:数据域、指针域
一、单向链表的创建、插入、遍历、查找、排序、逆序、删除、释放
例:typedef struct student{ int num;
float score;
struct student *next;
}STU;
1、链表的创建
添加节点到链表到链表的尾部:1)当链表为空时,将链表的头直接指向待添加的新节点2)链表不为空时,首先遍历链表找到链表的尾节点,然后将待添加的新节点挂在尾节点上
STU *head,*new;
new=(STU *)malloc(sizeof(STU));
void link_create(STU **head,STU *new)
{
//先定义一个中间变量,来保证头文件不变
STU *p_mov=*head;
if(*head==NULL)//插入第一个节点
{
*head=new;
new->next=NULL;
}
else
{
while(p_mov->next!=NULL)//找到尾节点
{
p_mov=p_mov->next;
}
p_mov->next=new;//将新节点添加到尾节点
new->next=NULL;
}
}
添加节点到链表到链表的头部
void link_create(STU **head,STU *new)
{
if(*head==NULL)//插入第一个节点
{
*head=new;
new->next=NULL;
}
else
{
new->next=*head;
*head=new->next;
}
}
2、链表的遍历 :遍历输出链表所有节点
1)得到链表第一个节点的地址,即头结点 2)设一个临时指针变量p_mov,指向第一个节点head,即获得p_mov所指节点的信息 3)使p_mov指向下一个节点
void link_print(STU *p_head)
{
STU *p_mov;
p_mov=p_head;
while(p_mov!=NULL)
{
printf("num=%d name= %s score=%d\n",p_mov->num,p_mov->name,p_mov->score);
p_mov=p_mov->next;
}
}
3、查找关键字:按照指定关键字查找所需节点
1)得到链表的第一个节点的地址,即头结点 2)设一个临时指针变量p_mov,指向第一个节点head,即获得p_mov所指节点的信息 3)比较是否是要查找的节点
STU *link_search_name(STU *head,char *name)
{
STU *p_mov;
p_mov=p_head;
while(p_mov!=NULL)
{
if(strcmp(p_mov->name,name)==0)
{
return p_mov;
}
else
p_mov=p_mov->next;
}
return NULL;
}
4、释放链表(从头节点一个一个的删除节点)
1)释放节点前要先保存下一节点,即将下一节点的地址赋值给p_movSTU * link_free(STU **head)
{
STU *p_mov;
p_mov=*head;
while(*head!=NULL)
{
p_mov=*head;
*head=*head->next;
free(p_mov);
}
return NULL;
}
5、删除节点
1)删除的是第一个节点,只需使head指向下一个节点2)删除的不是第一个节点,使被删除节点的前个节点指向后一个节点
void link_delete_num(STU **p_head,int num)
{
//先定义2个指针,用来保存上一个节点和下一个节点,即该节点的上一节点的next指向该节点的
下一节点
STU *pb,pf;
pb=pf=*p_head;
if(*p_head==NULL)
{
printf("该链表为空,没有要删除的节点\n");
return ;
}
while(pb->num!=num && pb->next!=NULL)
{
pf=pb;
pb=pb->next;
}
if(pb->num==num)
{
if(pb==*p_head)
{
*p_head=pb->next;
}
else
{
pf->next=pb->next;
}
free(pb);
}
else
{
printf("没有您要删除的节点\n");
}
}
6、插入节点
1、链表为空时,插入节点即为头结点 2、查找3、找到(插在头或插在一般位置)或者找不到(查到最后)void link_insert_num(STU** head,STU* new)
{
STU *pb,*pf;
pb=pf=*head;
if(*head==NULL)
{
*head=new;
new->next=NULL;
}
while((new->num<=pb->num)&&(pb->next)!=NULL)
{
pf=pb;
pb=pb->next;
}
if(new->num >pb->num)
{
if(pb==*head)
{
new->next=*head;
*head=new;
}
else
{
pf->next=new;
new->next=pb;
}
}
else
{
pb->next=new;
new->next=NULL;
}
}
7、排序
void link_order_num(STU **head){
STU *pb,*pf,temp;
pb=pf=head;
if(head==NULL)
{
printf("链表为空\n");
return 0;
}
while(pf->next!=NULL)
{
pb=pf->next;
while(pb!=NULL)
{
if(pb->num < pf->num)
{
temp=*pf;
*pf=*pb;
*pb=temp;
temp->next=pf->next;
pf->next=pb->next;
pb->next=pf->next;
}
pb=pb->next;
}
pf=pf->next;
}
}
8、逆序
STU *link_rever_num(STU *head){
STU *pb,*pf,*r;
pb=pf=head;
if(head==NULL)
{
printf("链表为空\n");
return 0;
}
if(head->next==NULL)
{
printf("链表只有一个节点,不用逆序\n");
return 0;
}
pb=pf->next;
while(pb!=NULL)
{
r = pb->next;
pb->next=pf;
pf=pb;
pb=r;
}
head->next=NULL;
head=pf;
return 0;
}
二、双向链表
#include <stdio.h>
#include <stdlib.h>
typedef struct student
{ //数据域
int num; //学号
int score; //分数
char name[20];
struct student *front;
struct student *next;//指针域
}STU;
/*****************双向链表的创建*****************************/
void double_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->front=NULL;
p_new->next=NULL;
}
else //第二次及以后加入链表
{
while(p_mov->next!=NULL)
{
p_mov=p_mov->next; //找到原有链表的最后一个节点
}
p_mov->next=p_new; //将新申请的节点加入链表
p_new->front=p_mov;
p_new->next=NULL;
}
}
/*****************双向链表的遍历******************************/
void double_link_print(STU *head)
{
STU *pb;
pb=head;
if(head==NULL)
{
printf("链表为空\n");
return ;
}
while(pb->next!=NULL)
{
printf("num=%d score=%d name:%s\n",pb->num,pb->score,pb->name);
pb=pb->next;
}
printf("num=%d score=%d name:%s\n",pb->num,pb->score,pb->name);
printf("\n\n\n\n");
while(pb!=NULL)
{
printf("num=%d score=%d name:%s\n",pb->num,pb->score,pb->name);
pb=pb->front;
}
}
/**********************双向链表的插入******************************/
void double_link_insert_num(STU **p_head,STU *p_new)
{
STU *pb,*pf;
pb=*p_head;
if(*p_head == NULL)//链表为空,新来的节点就是头节点
{
*p_head=p_new;
p_new->front=NULL;
p_new->next=NULL;
return ;
}
while((p_new->num >= pb->num) && (pb->next!=NULL) )
{
pb=pb->next ;
}
if(p_new->num < pb->num)//找到了一个pb的num比新来的节点的num大,插在pb前边
{
if(pb==*p_head)//找到的节点是头节点,插在头节点的前边
{
p_new->next=*p_head;
(*p_head)->front=p_new;
p_new->front=NULL;
*p_head=p_new;
}
else
{
pf=pb->front;//pf指向 找到节点的前一个节点
p_new->next=pb;
p_new->front=pf;
pf->next=p_new;
pb->front=p_new;
}
}
else//所有pb指向节点的num都比p_new指向的节点的num小,插在最后
{
pb->next=p_new;
p_new->front=pb;
p_new->next=NULL;
}
}
int main()
{
STU *head=NULL,*p_new=NULL;
int num,i;
printf("请输入链表初始个数:\n");
scanf("%d",&num);
for(i=0;i<num;i++)
{
p_new=(STU*)malloc(sizeof(STU));//申请一个新节点
printf("请输入学号、分数、名字:\n"); //给新节点赋值
scanf("%d %d %s",&p_new->num,&p_new->score,p_new->name);
double_link_creat_head(&head,p_new); //将新节点加入链表
}
double_link_print(head);
while(1)
{
p_new=(STU*)malloc(sizeof(STU));//申请一个新节点
printf("请输入您要插入的节点的num score name\n");
scanf("%d %d %s",&p_new->num,&p_new->score,p_new->name);
double_link_insert_num(&head,p_new);
double_link_print(head);
}
}