【数据结构】双向链表的接口实现(附图解和源码)

双向链表的接口实现(附图解和源码)



前言

本文主要介绍双向链表中增删查改等接口实现,结尾附总源码


一、定义结构体

在这里插入图片描述

代码如下(示例):

typedef int LTDataType;
typedef struct ListNode
{
    
    
	LTDataType data;
	struct ListNode* prev;
	struct ListNode* next;
}ListNode;

二、接口实现(附图解+源码)

在这里插入图片描述

这里一共10个接口,我会我都会一 一为大家讲解(图解+源码


1.初始化双向链表

初始化出一个哨兵位的头结点(用malloc开辟),next和prev都指向自己。具体如下图!
在这里插入图片描述
在这里插入图片描述

代码如下(示例):

ListNode* ListInit()
{
    
    
	ListNode* p = (ListNode*)malloc(sizeof(ListNode));
	if (p == NULL)
	{
    
    
		perror(errno);
	}
	ListNode* phead = p;
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

2.开辟新空间

(1)开辟一个链表类型的动态空间,将地址给newnode;
(2)将值放入 newnode 的 data 数据内;
(3)将 newnode 的 next 和 prev 都置为NULL;
注意:1.将malloc开辟空间存到 newnode 里面时,参数为结构体所占的字节大小!2.对 newnode 进行 NULL 判断!

代码如下(示例):

ListNode* BuyListNode(LTDataType x)
{
    
    
	ListNode* p = (ListNode*)malloc(sizeof(ListNode));
	if (p == NULL)
	{
    
    
		perror(errno);
	}
	ListNode* newNode = p;
	newNode->data = x;
	newNode->next = NULL;
	newNode->prev = NULL;
	return newNode;
}

3.尾插数据

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


代码如下(示例):

void ListPushBack(ListNode* phead, LTDataType x)//尾插数据
{
    
    
	ListNode* tail = phead->prev;
	ListNode* newnode = BuyListNode(x);

	//第一个链接
	tail->next = newnode;
	newnode->prev = tail;
	//第二个链接
	phead->prev = newnode;
	newnode->next = phead;
}

4.尾删数据

这里需要两次进行断言:
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


代码如下(示例):

void ListPopBack(ListNode* phead)//尾删
{
    
    
	assert(phead);
	assert(phead->next != phead);

	ListNode* tail = phead->prev;
	ListNode* tailprev = tail->prev;
	free(tail);

	//连接
	tailprev->next = phead;
	phead->prev = tailprev;
}

5.打印双向链表中数据

在这里插入图片描述


代码如下(示例):

void ListPrint(ListNode* phead)//打印数据
{
    
    
	assert(phead);
	ListNode* cur = phead->next;
	while (cur != phead)
	{
    
    
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

6.头插数据

头插数据也是很简单的一个接口,链接两次即可,如下图
在这里插入图片描述


代码如下(示例):

void ListPushFront(ListNode* phead, LTDataType x)//头插
{
    
    
	assert(phead);
	ListNode* newNode = BuyListNode(x);
    ListNode* next = phead->next;
	phead->next = newNode;
	newNode->prev = phead;
	newNode->next = next;
	next->prev = newNode;
}

7.头删数据

在头删数据时和尾删数据一样都需要进行两次断言如下图!
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


代码如下(示例):

void ListPopFront(ListNode* phead)//头删
{
    
    
	assert(phead);
	assert(phead->next != phead);

	ListNode* next = phead->next;
	ListNode* nextNext = next->next;

	phead->next = nextNext;
	nextNext->prev = phead;
	free(next);
}

8.查找结点位置

这个比较简单,和单链表一样,直接用cur遍历即可,直接上代码

代码如下(示例):

ListNode* ListFind(ListNode* phead, LTDataType x)
{
    
    
	assert(phead);
	ListNode* cur = phead->next;
	while (cur != phead)
	{
    
    
		if (cur->data == x)
		{
    
    
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

9.在pos位置之前插入

在这里插入图片描述


在这里插入图片描述


代码如下(示例):

void ListInsert(ListNode* pos, LTDataType x)//pos位置之前插入
{
    
    
	assert(pos);
	ListNode* newNode = BuyListNode(x);
	ListNode* posPrev = pos->prev;

	// posPrev  newnode pos
	posPrev->next = newNode;
	newNode->prev = posPrev;
	newNode->next = pos;
	pos->prev = newNode;
}

根据ListInsert接口我们可以把头插和尾插进行改版,如下图!
在这里插入图片描述


在这里插入图片描述


10.删除pos位置

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


代码如下(示例):

void ListErase(ListNode* pos)//删除pos位置
{
    
    
	assert(pos);
	ListNode* prev = pos->prev;
	ListNode* next = pos->next;
	free(pos);
	pos = NULL;
	prev->next = next;
	next->prev = prev;
}

11.销毁双向链表

在这里插入图片描述


在这里插入图片描述


代码如下(示例):

void ListDestory(ListNode* phead)
{
    
    
	assert(phead);
	ListNode* cur = phead->next;
	while (cur != phead)
	{
    
    
		ListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	free(phead);
	phead = NULL;
}

三、源代码展示

1.test.c(测试+主函数)

代码如下(示例):

#include "list.h"
void Testlist1()
{
    
    
	ListNode* n1 = ListInit();
	ListPushBack(n1, 1);//尾插
	ListPushBack(n1, 2);//尾插
	//ListPushBack(n1, 3);//尾插
	//ListPushBack(n1, 4);//尾插
	//ListPushBack(n1, 5);//尾插
	//ListPopFront(n1);//头删
	//ListPopBack(n1);//尾删
	//ListPushFront(n1, 0);//头插
	ListPrint(n1);
}
void Testlist2()
{
    
    
	ListNode* n1 = ListInit();
	ListPushBack(n1, 1);//尾插
	ListPushBack(n1, 2);//尾插
	ListPushBack(n1, 3);//尾插
	ListPushBack(n1, 4);//尾插
	ListPushBack(n1, 5);//尾插
	ListNode* p = ListFind(n1, 5);
	printf("%d \n", p->data);
}
void Testlist3()
{
    
    
	ListNode* n1 = ListInit();
	ListPushBack(n1, 1);//尾插
	ListPushBack(n1, 2);//尾插
	ListPushBack(n1, 3);//尾插
	ListPushBack(n1, 4);//尾插
	ListPushBack(n1, 5);//尾插
	//ListNode* p = ListFind(n1, 5);
	//ListInsert(p, 0);
	ListDestory(n1);
	ListPrint(n1);
}
int main()
{
    
    
	//Testlist1();
	//Testlist2();
	Testlist3();
	return 0;
}

2.List.h(接口函数的声明)

代码如下(示例):

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
typedef int LTDataType;
typedef struct ListNode
{
    
    
	LTDataType data;
	struct ListNode* prev;
	struct ListNode* next;
}ListNode;
ListNode* ListInit();//初始化双向链表
void ListPushBack(ListNode* phead, LTDataType x);//尾插
void ListPopBack(ListNode* phead);//尾删
void ListPushFront(ListNode* phead, LTDataType x);//头插
void ListPopFront(ListNode* phead);//头删
void ListPrint(ListNode* phead);//打印
ListNode* ListFind(ListNode* phead, LTDataType x);//查找数据
void ListInsert(ListNode* pos, LTDataType x);//pos位置之前插入
void ListErase(ListNode* pos);//删除pos位置
void ListDestory(ListNode* phead);//销毁双向链表

3.List.c(接口函数的实现)

代码如下(示例):

#include "list.h"
ListNode* ListInit()
{
    
    
	ListNode* p = (ListNode*)malloc(sizeof(ListNode));
	if (p == NULL)
	{
    
    
		perror(errno);
	}
	ListNode* phead = p;
	phead->next = phead;
	phead->prev = phead;
	return phead;
}
ListNode* BuyListNode(LTDataType x)
{
    
    
	ListNode* p = (ListNode*)malloc(sizeof(ListNode));
	if (p == NULL)
	{
    
    
		perror(errno);
	}
	ListNode* newNode = p;
	newNode->data = x;
	newNode->next = NULL;
	newNode->prev = NULL;
	return newNode;
}
void ListPushBack(ListNode* phead, LTDataType x)//尾插数据
{
    
    
	ListNode* tail = phead->prev;
	ListNode* newnode = BuyListNode(x);

	//第一个链接
	tail->next = newnode;
	newnode->prev = tail;
	//第二个链接
	phead->prev = newnode;
	newnode->next = phead;
	//ListInsert(phead, x);
}
void ListPrint(ListNode* phead)//打印数据
{
    
    
	assert(phead);
	ListNode* cur = phead->next;
	while (cur != phead)
	{
    
    
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}
void ListPopBack(ListNode* phead)//尾删
{
    
    
	assert(phead);
	assert(phead->next != phead);

	ListNode* tail = phead->prev;
	ListNode* tailprev = tail->prev;
	free(tail);

	//连接
	tailprev->next = phead;
	phead->prev = tailprev;
}
void ListPushFront(ListNode* phead, LTDataType x)//头插
{
    
    
	assert(phead);
	ListNode* newNode = BuyListNode(x);
	ListNode* next = phead->next;
	phead->next = newNode;
	newNode->prev = phead;
	newNode->next = next;
	next->prev = newNode;
	//ListInsert(phead->next, x);
}
void ListPopFront(ListNode* phead)//头删
{
    
    
	assert(phead);
	assert(phead->next != phead);

	ListNode* next = phead->next;
	ListNode* nextNext = next->next;

	phead->next = nextNext;
	nextNext->prev = phead;
	free(next);
}
ListNode* ListFind(ListNode* phead, LTDataType x)
{
    
    
	assert(phead);
	ListNode* cur = phead->next;
	while (cur != phead)
	{
    
    
		if (cur->data == x)
		{
    
    
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}
void ListInsert(ListNode* pos, LTDataType x)//pos位置之前插入
{
    
    
	assert(pos);
	ListNode* newNode = BuyListNode(x);
	ListNode* posPrev = pos->prev;

	// posPrev  newnode pos
	posPrev->next = newNode;
	newNode->prev = posPrev;
	newNode->next = pos;
	pos->prev = newNode;
}
void ListErase(ListNode* pos)//删除pos位置
{
    
    
	assert(pos);
	ListNode* prev = pos->prev;
	ListNode* next = pos->next;
	free(pos);
	pos = NULL;
	prev->next = next;
	next->prev = prev;
}
void ListDestory(ListNode* phead)
{
    
    
	assert(phead);
	ListNode* cur = phead->next;
	while (cur != phead)
	{
    
    
		ListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	free(phead);
	phead = NULL;
}

总结

以上就是今天要讲的内容,本文介绍双向链表的接口实现(附图解和源码)。
如果我的博客对你有所帮助记得三连支持一下,感谢大家的支持!
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/2201_75587702/article/details/129215687