day20 双向链表

发布于:2025-07-25 ⋅ 阅读:(17) ⋅ 点赞:(0)

双向链表的函数功能


注意事项 

1.双向链表还需要关注到前指针的指向

2.函数都需要判断逻辑

3.函数的增删都要关注到len的变化

4.函数的改查功能都需要遍历结束的标志NULL

5.注意p->next->prio时,p->next是否指向NULL

创建双向链表头节点

Node_ptr list_create()

函数功能:申请一个头结点初始化len

参数:无

返回值:头结点地址

    //指针接收申请的空间地址
	Node_ptr L=(Node_ptr)malloc(sizeof(Node));	
	//判断逻辑
	if(L==NULL)
	{
		printf("申请空间失败\n");
		return NULL;
	}
	//初始化逻辑
	L->len=0;
	L->prio=NULL;
	L->next=NULL;
	//返回逻辑
	return L;

判空函数

int list_empty(Node_ptr head)

函数功能:判断双向链表是否为空
参数:头结点地址
返回值:链表为空返回1,非空返回0 

return L->next==NULL;

节点封装函数

Node_ptr list_node_apply(datatype e)

函数功能:申请一个新节点初始化数据域为e
参数:待封装的数据e
返回值:新节点地址

    //申请空间
	Node_ptr p=(Node_ptr)malloc(sizeof(Node));
	//判断逻辑
	if(p==NULL)
	{
		printf("节点空间申请失败\n");
		return NULL;
	}
	//初始化逻辑
	p->data=e;
	p->prio=NULL;
	p->next=NULL;
	//返回逻辑
	return p;

头插函数

int list_insert_head(Node_ptr head, datatype e)

函数功能:在链表头部插入新节点
参数:头结点地址,待插入数据e
返回值:成功返回1,失败返回0

    //节点申请
	Node_ptr p=list_node_apply(e);
	//头插逻辑
	if(list_empty(L))
	{
		//链表为空
		L->next=p;
		p->prio=L;
		//长度自增
		L->len++;
		return 0;
	}
	else
	{    
        //链表不为空
		//先确定尾指针的指向
		p->next=L->next;
		L->next=p;
		//再确定头指针的指向
		p->prio=L;
		p->next->prio=p;
		//长度自增
		L->len++;
		//返回逻辑
		printf("头插成功\n");
		return 0;
	}

尾插函数 

int list_insert_tail(Node_ptr head,datatype e);

函数功能:在链表尾部插入新节点
参数:头结点地址,待插入数据e
返回值:成功返回1,失败返回0

    //节点申请
	Node_ptr p=list_node_apply(e);
	if(p==NULL)
	{
		printf("尾插失败\n");
		return -1;
	}
	//遍历逻辑
	Node_ptr q=L->next;
	while(q->next!=NULL) //遍历到最后一个节点
	{
		q=q->next;
	}
	//插入逻辑
	p->next=q->next;
	q->next=p;
	p->prio=q;
	//长度自增
	L->len++;

 

遍历函数

void list_show(Node_ptr head)

函数功能:打印双向链表所有节点的数据
参数:头结点地址
返回值:无

按位置查找节点

Node_ptr list_search_post(Node_ptr head, int post)

函数功能:查找链表中指定位置的节点
参数:头结点地址,位置pos(从1开始)
返回值:找到返回节点地址,失败返回NULL

任意位置插入

int list_insert_post(Node_ptr head, int post, datatype e)

函数功能:在指定位置插入新节点
参数:头结点地址,位置post,待插入数据e
返回值:成功返回1,失败返回0

判断逻辑

申请空间

插入逻辑 

表长变化

返回逻辑

    //申请空间
	Node_ptr q=list_node_apply(e);
	if(q==NULL)
	{
		printf("插入失败1\n");
		return -1;
	}
	//post位置查找
	Node_ptr post_ptr=list_search_post(L,post);
	//插入逻辑
	//继承post节点的指向
	q->prio=post_ptr->prio;
	q->prio->next=q;
	//完善链接q的指向
	q->next=post_ptr;
	post_ptr->prio=q;
	//表长变化
	L->len++;
	//返回逻辑
	return 0;	

头删函数

int list_delete_head(Node_ptr head)

函数功能:删除链表首元素节点
参数:头结点地址
返回值:成功返回1,失败返回0

    Node_ptr p=L->next;
	//删除逻辑
	L->next=p->next;
	if(L->next!=NULL)
	L->next->prio=L;
	//释放节点,置空
	free(p);
	p=NULL;
	//len自减逻辑
	L->len--;

尾删函数

 int list_delete_tail(Node_ptr L)

函数功能:删除链表尾元素节点
参数:头结点地址
返回值:成功返回1,失败返回0

    //遍历逻辑
	Node_ptr p=L->next;
	while(p->next!=NULL) //遍历到最后一个节点
	{
		p=p->next;
	}
	//删除逻辑
	p->prio->next=NULL; //倒数第二个节点置空
	//长度自减
	L->len--;

 

任意位置删除

int list_delete_post(Node_ptr head, int post)

函数功能:删除指定位置的节点
参数:头结点地址,位置pos
返回值:成功返回1,失败返回0

    //查找逻辑
	Node_ptr p=list_search_post(L,post);
	//删除逻辑
	//最后一个节点只执行一条
	p->prio->next=p->next;
	if(p->next!=NULL)
	{   
		//如果不为最后一个节点
		p->next->prio=p->prio;
	}
	//自减
	L->len--;
	//释放节点,置空
	free(p);
	p=NULL;

任意位置修改

int list_updata_post(Node_ptr head, int post, datatype e)

函数功能:修改指定位置节点的数据
参数:头结点地址,位置pos,新数据e
返回值:成功返回1,失败返回0

    //查找逻辑
	Node_ptr p=list_search_post(L,post);
	//修改逻辑
	p->data=e;

销毁链表

int list_free(Node_ptr head)

函数功能:释放双向链表所有节点内存
参数:头结点地址
返回值:成功返回1,失败返回0

    //删除逻辑
	//结点删除 
	Node_ptr p=L->next;
	while(!list_empty(L))
	{
		list_delete_head(L);	
	}
	//头节点删除
	free(L);
	L=NULL;

链表与顺序表的比较

存储:1.顺序表是一段连续空间存储,链表不一定连续的空间

           2.顺序表是静态分配空间,链表是动态分配空间        (创建时体现)

           3.顺序表存在存满的情况,链表不存在

           4.顺序表需要提前预估空间,链表不需要

时间复杂度
增删 改查
顺序表 O(n)      其他数据元素后移 O(1)        对应的元素修改即可
链表            O(1)      只需改变指针指向 O(n)        需要遍历到其位置

因此:增删链表,改查顺序表

完整代码

Dlink.h

#ifndef _Dlink_H
#define _Dlink_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef char datatype;//定义数据类型
//双向链表
typedef struct Node
{   
	//数据域
	union
	{
		datatype data;
		int len;
	};
	//指针域
	struct Node *prio;   //前指针
	struct Node *next;   //后指针
}Node,*Node_ptr;   

//创建双向链表头节点
Node_ptr list_create();

//判空
int list_empty(Node_ptr );

//节点封装函数
Node_ptr list_node_apply(datatype e);

//头插
int list_insert_head(Node_ptr ,datatype );

//尾插
int list_insert_tail(Node_ptr,datatype);
//遍历
void list_show(Node_ptr );

//按位置查找返回节点(位置从1开始)
Node_ptr list_search_post(Node_ptr ,int);

//任意位置插入数据
int list_insert_post(Node_ptr ,int ,datatype);

//头删
int list_delete_head(Node_ptr );
//尾删
int list_delete_tail(Node_ptr );
//任意位置删除
int list_delete_post(Node_ptr ,int );

//任意位置修改
int list_updata_post(Node_ptr ,int ,datatype);

//销毁双向链表
int list_free(Node_ptr );
#endif

Dlink.c

#include"Dlink.h"

//创建双向链表
Node_ptr list_create()
{   
	//指针接收申请的空间地址
	Node_ptr L=(Node_ptr)malloc(sizeof(Node));	
	//判断逻辑
	if(L==NULL)
	{
		printf("申请空间失败\n");
		return NULL;
	}
	//初始化逻辑
	L->len=0;
	L->prio=NULL;
	L->next=NULL;
	//返回逻辑
	return L;
}
//判空
//空返回1,非空返回0,非法返回-1
int list_empty(Node_ptr L)
{   //判断逻辑
	if(L==NULL)
	{
		printf("非法地址\n");
		return -1;
  	}
	return L->next==NULL;
}
//节点封装函数
Node_ptr list_node_apply(datatype e)
{
	//申请空间
	Node_ptr p=(Node_ptr)malloc(sizeof(Node));
	//判断逻辑
	if(p==NULL)
	{
		printf("节点空间申请失败\n");
		return NULL;
	}
	//初始化逻辑
	p->data=e;
	p->prio=NULL;
	p->next=NULL;
	//返回逻辑
	return p;
}


//头插
//成功返回0,失败返回-1
int list_insert_head(Node_ptr L,datatype e)
{
	//判断逻辑
	if(L==NULL)
	{
		printf("非法地址\n");
		return -1;
	}
	//节点申请
	Node_ptr p=list_node_apply(e);
	//头插逻辑
	if(list_empty(L))
	{
		//链表为空
		L->next=p;
		p->prio=L;
		printf("插入成功\n");
		//长度自增
		L->len++;
		return 0;
	}
	else
	{
		//先确定尾指针的指向
		p->next=L->next;
		L->next=p;
		//再确定头指针的指向
		p->prio=L;
		p->next->prio=p;
		//长度自增
		L->len++;
		//返回逻辑
		printf("头插成功\n");
		return 0;
	}
}
//尾插
int list_insert_tail(Node_ptr L,datatype e)
{
	//判断逻辑
	if(L==NULL)
	{
		printf("尾插失败\n");
		return -1;
	}
	//节点申请
	Node_ptr p=list_node_apply(e);
	if(p==NULL)
	{
		printf("尾插失败\n");
		return -1;
	}
	//遍历逻辑
	Node_ptr q=L->next;
	while(q->next!=NULL) //遍历到最后一个节点
	{
		q=q->next;
	}
	//插入逻辑
	p->next=q->next;
	q->next=p;
	p->prio=q;
	//长度自增
	L->len++;
	//返回逻辑
	return 0;
}

//遍历
void list_show(Node_ptr L)
{
	//判断逻辑
	if(L==NULL)
	{
		printf("非法地址\n");
	}
	//遍历逻辑
	Node_ptr p=L->next; //定义遍历指针
	while(p!=NULL)
	{
		printf("%-4c",p->data); //访问数据域
		p=p->next;//指针移到下一个节点
	}
	putchar(10);
}
	
//按位置查找返回节点(位置从1开始)
Node_ptr list_search_post(Node_ptr L,int post)
{
	//判断逻辑
	if(list_empty(L)||post<1||post>L->len)
	{
		printf("post不合理\n");
		return NULL;
	}
	//查找逻辑
	Node_ptr p=L->next;
	for (int i=1; i<post; i++)
	{
		p=p->next;
	}
	return p;
}
//任意位置插入数据
int list_insert_post(Node_ptr L,int post,datatype e)
{
	//判断逻辑
	if(post<1||post>L->len+1)
	{
		printf("插入位置不合理\n");
		return -1;
	}
	//申请空间
	Node_ptr q=list_node_apply(e);
	if(q==NULL)
	{
		printf("插入失败1\n");
		return -1;
	}
	//post位置查找
	Node_ptr post_ptr=list_search_post(L,post);
	//插入逻辑
	//继承post节点的指向
	q->prio=post_ptr->prio;
	q->prio->next=q;
	//完善链接q的指向
	q->next=post_ptr;
	post_ptr->prio=q;
	//表长变化
	L->len++;
	//返回逻辑
	return 0;		
}

//头删
int list_delete_head(Node_ptr L)
{
	//判断逻辑
	if(list_empty(L))
	{
		printf("头删失败\n");
		return -1;
	}
	Node_ptr p=L->next;
	//删除逻辑
	L->next=p->next;
	if(L->next!=NULL)
	L->next->prio=L;
	//释放节点,置空
	free(p);
	p=NULL;
	//len自减逻辑
	L->len--;
	//返回逻辑
	return 0;
}
//尾删
int list_delete_tail(Node_ptr L)
{
	//判断逻辑
	if(L==NULL||list_empty(L))
	{
		printf("尾删失败\n");
		return -1;
	}
	//遍历逻辑
	Node_ptr p=L->next;
	while(p->next!=NULL) //遍历到最后一个节点
	{
		p=p->next;
	}
	//删除逻辑
	p->prio->next=NULL; //倒数第二个节点置空
	//长度自减
	L->len--;
	//返回逻辑
	printf("尾删成功\n");
	return 0;
	
}
//任意位置删除
int list_delete_post(Node_ptr L,int post )
{
	//判断逻辑
	if(list_empty(L)||post<1||post>L->len)
	{
		printf("位置删除失败\n");
		return -1;
	}
	//查找逻辑
	Node_ptr p=list_search_post(L,post);
	//删除逻辑
	//最后一个节点只执行一条
	p->prio->next=p->next;
	if(p->next!=NULL)
	{   
		//如果不为最后一个节点
		p->next->prio=p->prio;
	}
	//自减
	L->len--;
	//释放节点,置空
	free(p);
	p=NULL;
	//返回逻辑
	return 0;
}
//任意位置修改
int list_updata_post(Node_ptr L ,int post ,datatype e)
{
	//判断逻辑
	if(list_empty(L)||post<1||post>L->len)
	{
			printf("修改位置不合理\n");
			return -1;
	}
	//查找逻辑
	Node_ptr p=list_search_post(L,post);
	//修改逻辑
	p->data=e;
	//返回逻辑
	return 0;
}
//销毁双向链表
int list_free(Node_ptr L)
{
	//判断逻辑
	if(L==NULL)
	{
		printf("销毁失败\n");
		return -1;
	}
	//删除逻辑
	//结点删除 
	Node_ptr p=L->next;
	while(!list_empty(L))
	{
		list_delete_head(L);	
	}
	//头节点删除
	free(L);
	L=NULL;
	//返回逻辑
	printf("销毁成功\n");
	return 0;
}

 Dmain.c

#include"Dlink.h"
int main(int argc, const char *argv[])
{		
	//接收申请的空间
	Node_ptr x=list_create();
	if(x==NULL)
	{
		printf("申请失败\n");
		return -1;
	}
	printf("申请成功\n");
	//头插
	printf("-----------头插-----------\n");
	list_insert_head(x,'a');
	list_insert_head(x,'b');
	list_insert_head(x,'c');
	list_insert_head(x,'d');
	list_insert_head(x,'e');
	list_insert_head(x,'f');
	list_insert_head(x,'p');
	list_insert_head(x,'q');
	printf("-----------遍历------------\n");
	list_show(x);
	printf("------按位置查找-----------\n");
	Node_ptr q=list_search_post(x,3);
	printf("%c\n",q->data);
	//按位置插入
	printf("--------位置插入-----------\n");
	list_insert_post(x,3,'x');
	list_insert_post(x,x->len,'z');
	list_show(x);
	//头删
	printf("----------头删-------------\n");
	list_delete_head(x);
	list_delete_head(x);
	list_show(x);
	//尾删
	printf("----------尾删-------------\n");
	list_delete_tail(x);
	list_delete_tail(x);
	list_show(x);
	//尾插
	printf("----------尾插-------------\n");
	list_insert_tail(x,'D');
	list_insert_tail(x,'O');
	list_show(x);
	//任意位置删除
	printf("-------位置删除------------\n");
	list_delete_post(x,x->len);
	list_delete_post(x,2);
	list_show(x);
	//任意位置修改
	printf("-------位置修改------------\n");
	list_updata_post(x,x->len,'G');
	list_show(x);
	printf("-------链表销毁------------\n");
	list_free(x);
	return 0;
}


网站公告

今日签到

点亮在社区的每一天
去签到