实现双向链表的头插、头删、尾插、尾删、按位置插入、按位置删除
double_list.h头文件代码:
#ifndef __DOUBLE_LIST_H__
#define __DOUBLE_LIST_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node
{
int data;
struct node *pri; //前一个结点地址
struct node *next; //后一个结点地址
}node,*node_p;
//创建双向链表
node_p create_double_list();
//创建结点
node_p create_node(int data);
//链表判空
int empty_double(node_p H);
//头插
void insert_head(node_p H,int data);
//尾插
void insert_tail(node_p H,int data);
//按位插入
void insert_pos(node_p H,int data,int pos);
//头删
void del_head(node_p H);
//尾删
void del_tail(node_p H);
//按位删除
void del_pos(node_p H,int pos);
//输出
void show_double(node_p H);
#endif
double_list.c自定义函数代码:
#include "double_list.h"
//创建双向链表
node_p create_double_list()
{
//申请空间
node_p H=(node_p)malloc(sizeof(node));
//判空
if(H==NULL)
{
printf("空间申请失败\n");
return NULL;
}
//创建头结点
//头结点数据位,记录结点数,初始值0
H->data=0;
//前结点地址为NULL
H->pri=NULL;
//后结点地址为NULL
H->next=NULL;
}
//创建结点
node_p create_node(int data)
{
//申请空间
node_p new=(node_p)malloc(sizeof(node));
//判空
if(new==NULL)
{
printf("空间申请失败\n");
return NULL;
}
new->data=data;
return new;
}
//链表判空
int empty_double(node_p H)
{
//入参判空
if(H==NULL)
{
printf("入参为空\n");
return -1;
}
return H->next==NULL?1:0;
}
//头插
void insert_head(node_p H,int data)
{
//入参判空
if(H==NULL)
{
printf("入参为空\n");
return;
}
//创建新结点
node_p new=create_node(data);
//将new->next指向头结点next指向的地址
new->next=H->next;
//若第一个结点存在,则要将原第一个结点的pri指向new
if(H->next!=NULL)
H->next->pri=new;
//将新结点pri指向头结点地址
new->pri=H;
//将头结点next指向new
H->next=new;
//结点个数自增
H->data++;
}
//尾插
void insert_tail(node_p H,int data)
{
//入参判空
if(H==NULL)
{
printf("入参为空\n");
return;
}
//先找到尾结点
//定义一个结点,指向头结点
node_p p=H;
//循环找到尾节点
while(p->next!=NULL)
p=p->next;//指向下个结点
//最终p为尾节点
//创建新结点
node_p new=create_node(data);
//将new->next指向原尾节点next指向的地址,NULL
new->next=p->next;
//将new->pri指向原尾节点地址
new->pri=p;
//将原尾节点next指向new的地址
p->next=new;
//结点个数自增
H->data++;
return;
}
//按位插入
void insert_pos(node_p H,int data,int pos)
{
//入参判空
if(H==NULL)
{
printf("入参为空\n");
return;
}
//插入位置合理性判断
//pos表示插入第几个位置
if(pos<=0||pos>H->data+1)
{
printf("输入的位置不合理\n");
return;
}
//先找到pos-1位置的结点
//定义p,初始化为头结点地址
node_p p=H;
//循环找到pos-1位置地址
for(int i=0;i<pos-1;i++)
p=p->next;
//此时p为pos-1位置结点地址
//创建新结点
node_p new=create_node(data);
//new->next指向pos位置结点的地址
new->next=p->next;
//若pos位置结点地址不为NULL
//则要将pos结点的pri指向new地址
if(p->next!=NULL)
p->next->pri=new;
//新结点pri指向pos-1位置结点地址
new->pri=p;
//pos-1位置结点next指向新结点地址
p->next=new;
//结点个数自增
H->data++;
return;
}
//头删
void del_head(node_p H)
{
//入参判空
if(H==NULL)
{
printf("入参为空\n");
return;
}
//链表判空
if(empty_double(H))
{
printf("链表为空\n");
return;
}
//先保存要删除的结点
node_p del=H->next;
//定义结点,指向第二结点地址
node_p p=H->next->next;
//将头结点next指向第二个结点
H->next=p;
//若第二个结点不为NULL,需将第二个结点pri指向头结点
if(p!=NULL)
p->pri=H;
//释放掉要删除的结点空间
free(del);
//结点个数自减
H->data--;
return;
}
//尾删
void del_tail(node_p H)
{
//入参判空
if(H==NULL)
{
printf("入参为空\n");
return;
}
//链表判空
if(empty_double(H))
{
printf("链表为空\n");
return;
}
//先找到倒数第二个结点
node_p p=H;
while(p->next->next!=NULL)
p=p->next;
//此时p为倒数第二个结点地址
//保存要删除的结点
node_p del=p->next;
//将倒二结点next指向尾结点next指向的地址,NULL
p->next=p->next->next;
//释放掉要删除的结点空间
free(del);
//pri指针置空
del->pri=NULL;
//结点个数自减
H->data--;
return;
}
//按位删除
void del_pos(node_p H,int pos)
{
//入参判空
if(H==NULL)
{
printf("入参为空\n");
return;
}
//链表判空
if(empty_double(H))
{
printf("链表为空\n");
return;
}
//删除位置合理性判断
//pos表示删除第几个位置
if(pos<=0||pos>H->data)
{
printf("输入的位置不合理\n");
return;
}
//先找到pos-1位置的结点
//定义p,初始化为头结点地址
node_p p=H;
//循环找到pos-1位置地址
for(int i=0;i<pos-1;i++)
p=p->next;
//此时p为pos-1位置结点地址
//保存要删除的结点地址
node_p del=p->next;
//定义q,指向pos+1结点地址
node_p q=p->next->next;
//将pos-1结点next指向pos+1结点地址
p->next=q;
//若pos+1结点地址不为NULL,其pri需指向pos-1地址
if(q!=NULL)
q->pri=p;
//释放要删除的结点空间
free(del);
del->pri=NULL;
//结点个数自减
H->data--;
return;
}
//输出
void show_double(node_p H)
{
//入参判空
if(H==NULL)
{
printf("入参为空\n");
return;
}
//链表判空
if(empty_double(H))
{
printf("链表为空\n");
return;
}
//定义结点,指向第一个结点地址
node_p p=H->next;
while(p!=NULL)
{
printf("%d->",p->data);
p=p->next;
}
printf("NULL\n");
}
main.c主函数代码:
int main()
{
node_p H=create_double_list();
printf("判空为:%d\n",empty_double(H));
insert_head(H,10);
insert_head(H,20);
insert_head(H,30);
insert_head(H,40);
insert_head(H,50);
insert_head(H,60);
show_double(H);
insert_tail(H,70);
show_double(H);
insert_pos(H,33,2);
show_double(H);
insert_pos(H,22,100);
show_double(H);
del_head(H);
show_double(H);
del_tail(H);
show_double(H);
del_pos(H,4);
show_double(H);
return 0;
}
运行结果:
链表和顺序表的区别
1、逻辑结构相同:都是线性结构。
物理结构不同:顺序表是顺序结构,物理地址连续;链表是链式结构,物理地址不连续。
2、顺序表通过下标访问元素,链表通过指针访问元素
3、顺序表查询速度快,插入、删除速度慢;
链表查询速度慢,插入、删除速度快。