一、单向链表(含逆置)
head.h
#ifndef __HEAD_H__
#define __HEAD_H__
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct node
{
int date;
struct node *next;
}node,*node_p;
node_p creat_lik_list();//创建头节点
node_p new_node(int date);//创建节点
void insert_head(node_p H,int date);//头插
int empty_lik(node_p H);//判空
void show_lik(node_p H);//输出
void delete_head_lik(node_p H);//头删
void insert_tail(node_p H,int date);//尾插
void delete_tail(node_p H);//尾删
void insert_pos(node_p H,int pos,int date);//按位置插入
void delete_pos(node_p H,int pos);//按位置删除
node_p search_pos(node_p H,int pos);//按位置查找
void update_value(node_p H,int key,int date);//按位置修改
void replce_pos_value(node_p H,int pos,int date);//按位置替换
void overturn_lik(node_p H);//逆置
#endif
main.c
int main()
{
node_p H=creat_lik_list();
insert_head(H,11);
insert_head(H,22);
insert_tail(H,33);
insert_tail(H,44);
insert_tail(H,55);
insert_head(H,66);
delete_head_lik(H);
delete_tail(H);
insert_pos(H,2,77);
delete_pos(H,3);
show_lik(H);
printf("search=%d\n",*search_pos(H,2)->next);
replce_pos_value(H,3,66);
update_value(H,44,45);
show_lik(H);
overturn_lik(H);
show_lik(H);
}
test.c
#include"head.h"
node_p creat_lik_list()//创建头节点,创建链表,头节不存储值
{
node_p H =(node_p)malloc(sizeof(node));
if(H==NULL)
{
printf("apply to fail!\n");
return NULL;
}
H->next=NULL;//无节点指向空
H->date=0;
return H;
}
node_p new_node(int date)//创建节点,创建数据节点
{
node_p new =(node_p)malloc(sizeof(node));//申请节点地址
if(new==NULL)
{
printf("apply to fail!\n");
return NULL;
}
new->date=date;//节点赋值
return new;
}
void insert_head(node_p H,int date)
{
if(H==NULL)
{
printf("init error!\n");
return;
}
node_p new =new_node(date);//申请插入的值以及地址
new->next=H->next;//将头地址(NULL)赋值给申请节点内指针做保存,作为收尾
H->next=new;//将头节点内指针更新为申请的节点地址,把下一个节点的存储地址,放到上一个节点,更新头地址,前移
H->date++;//记录长度
}
int empty_lik(node_p H)
{
if(H==NULL)
{
printf("init error!\n");
return -1;
}
return H->next==NULL?1:0;
}
void show_lik(node_p H)
{
if(empty_lik(H))
{
printf("no input!\n");
return;
}
node_p p=H;//头节点的next表示第一个节点指针,需输出
while(p->next!=NULL)//链表节点最后一个的标志,参考头插逻辑
{
printf("%d->",p->next->date);
p=p->next;//当前节点的*next给p,该*next实际是下一个节点存储的实际位置(指针),换言之,当下次取p时,便到了下一个节点上
}
printf("NULL\n");
}
void delete_head_lik(node_p H)//头删是删除头节点下面的一个节点,该节点的指针是在头节点里,所以要删除该地址,并将该节点所包含的下一个节点的指针与头连接
{
if(empty_lik(H))
{
printf("input empty,don't delete!\n");
return;
}
node_p p=H->next;
H->next=H->next->next;//H->next是头节所存的地址,该地址也是下一个节点结构体申请的存储地址(下个节点的指针),所以H->next->next表示下一个节点内的*next
free(p);
H->date--;
}
void insert_tail(node_p H,int date)
{
if(H==NULL)
{
printf("init error!\n");
return;
}
node_p p=H;
while(p->next!=NULL)//找到最后的位置
{
p=p->next;
}
node_p new=new_node(date);
new->next=p->next;
p->next=new;
H->date++;
}
void delete_tail(node_p H)//删除最后一个元素,即倒数第二个节点存储的地址
{
if(empty_lik(H))
{
printf("input empty,don't delete!\n");
return;
}
node_p p=H;
while(p->next->next!=NULL)//前一个节点的next存放下一个节点申请的地址,再取next,便是下一个节点的next,换言之,判断下一个节点的地址
{
p=p->next;
}
node_p del =p->next;
p->next=p->next->next;
free(del);
H->date--;
}
void insert_pos(node_p H,int pos,int date)
{
if(empty_lik(H))
{
printf("input empty!\n");
return;
}
if(pos<=0||pos>H->date+1)
{
printf("input pos error!\n");
return;
}
node_p new=new_node(date);
node_p p=H;
for(int i=0;i<pos-1;i++)//确定循环次数用for,确定pos-1位置,pos为实际位置
{
p=p->next;
}
new->next=p->next;
p->next=new;
H->date++;
}
void delete_pos(node_p H,int pos)
{
if(empty_lik(H))
{
printf("input empty,don't delete!\n");
return;
}
if(pos<=0||pos>H->date)
{
printf("input pos error!\n");
return;
}
node_p p=H;
for(int i=0;i<pos-1;i++)
{
p=p->next;
}
node_p del=p->next;
p->next=p->next->next;
free(del);
H->date--;
}
node_p search_pos(node_p H,int pos)
{
if(empty_lik(H))
{
printf("input empty,no find!\n");
return NULL;
}
if(pos<=0||pos>H->date)
{
printf("input pos error!\n");
return NULL;
}
node_p p=H;
for(int i=0;i<pos-1;i++)
{
p=p->next;
}
return p;
}
void replce_pos_value(node_p H,int pos,int date)
{
if(empty_lik(H))
{
printf("input empty,no find!\n");
return;
}
if(pos<=0||pos>H->date)
{
printf("input pos error!\n");
return;
}
node_p new =new_node(date);
node_p p=search_pos(H,pos);
//node_p del=p->next;
//p->next=new;
p->next->date=new->date;
//new->next=del->next;//替换后,将该位置与后面连接
//free(del);
}
void update_value(node_p H,int key,int date)
{
if(empty_lik(H))
{
printf("input empty,no find!\n");
return;
}
node_p p=H;
node_p new=new_node(date);
while(p->next!=NULL)
{
if(p->next->date==key)
{
p->next->date=new->date;
return;
}
p=p->next;
}
}
void overturn_lik(node_p H)
{
if(empty_lik(H))
{
printf("input empty,don't overturn!\n");
return;
}
if(H->next->next==NULL)//只有一个元素无需逆置
{
printf("only one,don't overturn!\n");
return;
}
node_p p=H->next->next;//保存第二个点的地址,需要从第二个元素开始判断并且往前头插,需要一个原始元素作为参考,避免逆置的时候元素改变而引起整体改变
H->next->next=NULL;//第一点的指针域置空,变为最后一个节点
node_p q;
while(p!=NULL)//p为刚开始保存的地址
{
q=p->next;//头插前保留下一个要头插的首地址,此处为原始保存的p地址开始
p->next=H->next;//头插操作,不影响后面未进行头插的地址,从操作上看陆续向前逐一交换
H->next=p;
p=q;//指向下一个插入的节点,每进一次保存的位置后移一位
}
}
运行结果:
二、单向循环链表
head.h
#ifndef __HEAD_H__
#define __HEAD_H__
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct node
{
int date;
struct node *next;
}node,*node_p;
node_p creat_loop_list();//创建头
node_p creat_node(int date);//创建点
int empty_loop(node_p H);//判空
void insert_head_loop(node_p H,int date);//头插
void show_loop(node_p H);//输出
void insert_tail_loop(node_p H,int date);//尾插
void delete_head(node_p H);//头删
void insert_pos(node_p H,int pos,int date);//按位置插入
node_p single_delete_head(node_p H);//删除头节点
void no_head_show(node_p T);//删除头节点输出
#endif
main.c
#include"head.h"
int main()
{
node_p H=creat_loop_list();
insert_head_loop(H,11);
insert_tail_loop(H,22);
insert_tail_loop(H,33);
delete_head(H);
insert_pos(H,3,44);
show_loop(H);
node_p T=single_delete_head(H);
// H=NULL;
// show_loop(H);运行报段错误
no_head_show(T);
}
test.c
#include"head.h"
node_p creat_loop_list()
{
node_p H=(node_p)malloc(sizeof(node));
if(H==NULL)
{
printf("fail to apply!\n");
return NULL;
}
H->date=0;
H->next=H;
return H;
}
node_p creat_node(int date)
{
node_p new=(node_p)malloc(sizeof(node));
if(new==NULL)
{
printf("fail to apply!\n");
return NULL;
}
new->date=date;
return new;
}
int empty_loop(node_p H)
{
if(H==NULL)
{
printf("fail to apply!\n");
return -1;
}
return H==NULL?1:0;
}
void insert_head_loop(node_p H,int date)
{
if(H==NULL)
{
printf("init error!\n");
return;
}
node_p new=creat_node(date);
new->next=H->next;
H->next=new;
H->date++;
}
void show_loop(node_p H)
{
if(empty_loop(H))
{
printf("input empty,don't output!\n");
return;
}
node_p p=H;
while(p->next!=H)
{
printf("%d->",p->next->date);
p=p->next;
}
printf("H\n");
}
void insert_tail_loop(node_p H,int date)
{
if(H==NULL)
{
printf("init error!\n");
return;
}
node_p new=creat_node(date);
node_p p=H;
while(p->next!=H)
{
p=p->next;
}
new->next=p->next;
p->next=new;
H->date++;
}
void delete_head(node_p H)
{
if(empty_loop(H))
{
printf("input empty,don't delete!\n");
return;
}
node_p del =H->next;
H->next=H->next->next;
free(del);
H->date--;
}
void insert_pos(node_p H,int pos,int date)
{
if(empty_loop(H))
{
printf("input empty,don't insert!\n");
return;
}
if(pos<=0||pos>H->date+1)
{
printf("input pos error!\n");
return;
}
node_p new=creat_node(date);
node_p p=H;
for(int i=0;i<pos-1;i++)
{
p=p->next;
}
new->next=p->next;
p->next=new;
H->date++;
}
node_p single_delete_head(node_p H)
{
if(empty_loop(H))
{
printf("input empty,don't delete!\n");
return NULL;
}
node_p p=H;
while(p->next!=H)
{
p=p->next;
}
p->next=H->next;
node_p temp=H->next;//暂时保存,释放头时,该地址会丢失
free(H);
return temp;
}
void no_head_show(node_p T)
{
node_p p=T;
do
{
printf("%d->",p->date);
p=p->next;
}while(p!=T);//第一次循环不判断
printf("T\n");
}
运行结果:
三、链表与顺序表的区别
1、储存方式:链表的元素在内存中通过指针连接,不需要连续空间,存储空间是动态分配的,顺序表的元素是在内存顺序存储,通过数组下标访问,存储空间是顺序分配
2、访问效率:链表不支持随机访问,查找或访问需从头节点开始,访问效率低,顺序表支持随机访问,可通过数组下标访问,访问效率高
3、插入与删除操作:链表通过修改相关节点指针,具有较高效率,顺序表需要移动元素,效率低
4、空间利用率:链表每个元素都需要空间存储指针,空间利用率低
四、双向链表头插、头删、尾插、尾删、按位置插入、按位置删除
head.h
#ifndef __HEAD_H__
#define __HEAD_H__
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct node
{
int date;
struct node *next;
struct node *pri;
}node,*node_p;
node_p creat_double_link();
node_p creat_new_node(int date);
int empty_link(node_p H);
void insert_head(node_p H,int date);
void insert_tail(node_p H,int date);
void delete_head(node_p H);
void delete_tail(node_p H);
void insert_pos(node_p H,int pos,int date);
void delete_pos(node_p H,int pos);
void show_link(node_p H);
#endif
main.c
#include"head.h"
int main()
{
node_p H=creat_double_link();
insert_head(H,11);
insert_tail(H,22);
insert_tail(H,33);
insert_tail(H,44);
delete_head(H);
delete_tail(H);
insert_pos(H,2,55);
delete_pos(H,3);
show_link(H);
}
test.c
#include"head.h"
node_p creat_double_link()
{
node_p H=(node_p)malloc(sizeof(node));
if(H==NULL)
{
printf("fail to apply!\n");
return NULL;
}
H->next=NULL;
H->pri=NULL;
H->date=0;
return H;
}
node_p creat_new_node(int date)
{
node_p h=(node_p)malloc(sizeof(node));
if(h==NULL)
{
printf("new node fail to apply!\n");
return NULL;
}
h->date=date;
return h;
}
int empty_link(node_p H)
{
if(H==NULL)
{
printf("fail to apply!\n");
return -1;
}
return H==NULL?1:0;
}
void insert_head(node_p H,int date)
{
if(H==NULL)
{
printf("fail to apply!\n");
return;
}
node_p new=creat_new_node(date);
new->next=H->next;//插入的新节点,后继要保存它插入前头结点后的地址
if(H->next!=NULL)//只有头结点时,后面没有元素,无需连接前驱
{
H->next->pri=new;// 当已有元素时,需连接前驱,插入前该节点后移,插入后该节点的前驱要保存插入节点的地址
}
new->pri=H;//插入节点保存头节点地址
H->next=new;//更新头节点后继,使其保存下一个元素的地址(被插入节点)
H->date++;
}
void insert_tail(node_p H,int date)
{
if(H==NULL)
{
printf("fail to apply!\n");
return;
}
node_p new =creat_new_node(date);
node_p p=H;
while(p->next!=NULL)//找到最后一个节点
{
p=p->next;
}
new->next=NULL;
p->next=new;
new->pri=p;
H->date++;
}
void delete_head(node_p H)
{
if(empty_link(H))
{
printf("input empty,don't delete!\n");
return;
}
node_p del=H->next;//保存要删除的位置
H->next=H->next->next;
H->next->next->pri=H;
free(del);
H->date--;
}
void delete_tail(node_p H)
{
if(empty_link(H))
{
printf("input empty,don't delete!\n");
return;
}
node_p p=H;
while(p->next->next!=NULL)
{
p=p->next;
}
node_p del=p->next;
p->next=NULL;
free(del);
H->date--;
}
void insert_pos(node_p H,int pos,int date)
{
if(empty_link(H))
{
printf("input empty,don't inserting!\n");
return;
}
if(pos<=0||pos>H->date+1)
{
printf("input pos error!\n");
return;
}
node_p p=H;
node_p new=creat_new_node(date);
for(int i=0;i<pos-1;i++)
{
p=p->next;
}
new->next=p->next;
if(p->next!=NULL)//在最后插入,相当于尾插,此时插入元素后面没有元素,此条无需连接
{
p->next->pri=new;
}
p->next=new;
new->pri=p;
H->date++;
}
void delete_pos(node_p H,int pos)
{
if(empty_link(H))
{
printf("input empty,don't delete!\n");
return;
}
if(pos<=0||pos>H->date)
{
printf("input pos error!\n");
return;
}
node_p p=H;
for(int i=0;i<pos-1;i++)
{
p=p->next;
}
node_p del=p->next;
if(p->next->next!=NULL)//最后一个元素相当于尾删,无需连接后面的元素
{
p->next->next->pri=p;
}
p->next=p->next->next;
free(del);
H->date--;
}
void show_link(node_p H)
{
if(empty_link(H))
{
printf("input empty,don't ouput!\n");
return;
}
node_p p=H;
while(p->next!=NULL)
{
printf("%d->",p->next->date);
p=p->next;
}
printf("NULL\n");
}