[数据结构]:双链表(带头双向循环链表)增删查改功能的实现

1.带头双向循环链表

带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了。

逻辑结构如下图
在这里插入图片描述

2.带头双向循环链表增删查改的实现

(1)DoubleList.h 链表各项功能的接口及函数的声明

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int LTDataType;
typedef struct ListNode
{
    
    
    //值
	LTDataType data;
	//前驱指针
	struct ListNode* prev;
	//后驱指针
	struct ListNode* next;
}ListNode;

//创建返回链表的头节点
ListNode* ListCreat();
//链表的销毁
void ListDestory(ListNode* phead);
//动态申请一个节点
ListNode* BuyListNode(LTDataType x);
//打印链表
void ListPrint(ListNode* phead);
//尾插
void ListPushBack(ListNode* phead, LTDataType x);
//头插
//头插在第一个有效数据前面,头节点不存储有效数据
void ListPushFront(ListNode* phead, LTDataType x);
//尾删
void ListPopBack(ListNode* phead);
//头删
void ListPopFront(ListNode* phead);
//查找
ListNode* ListFind(ListNode* phead, LTDataType x);
//在pos之前插入x
void ListInsert(ListNode* pos, LTDataType x);
//删除pos位置节点
void ListErase(ListNode* pos);

(2)DoubleList.c 各个接口功能的实现

#include"DoubleList.h"

//创建返回链表的头节点
ListNode* ListCreat()
{
    
    
	ListNode* phead = (ListNode*)malloc(sizeof(ListNode));
	phead->prev = phead;
	phead->next = phead;
	return phead;
}
//链表的销毁
void ListDestory(ListNode* phead)
{
    
    
	ListNode* cur = phead->next;
	while (cur != phead)
	{
    
    
		ListNode* next = cur->next;
		ListErase(cur);
		cur = next;
	}
	free(phead);
	phead = NULL;
}
//动态申请一个节点
ListNode* BuyListNode(LTDataType x)
{
    
    
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	newnode->data = x;
	//新节点前后指向空
	newnode->next = NULL;
	newnode->prev = NULL;
	return newnode;
}
//打印链表
void ListPrint(ListNode* phead)
{
    
    
	assert(phead);
	ListNode* cur = phead->next;
	while (cur != phead)
	{
    
    
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}
//尾插
void ListPushBack(ListNode* phead, LTDataType x)
{
    
    
	assert(phead);
	ListNode* tail = phead->prev;
	ListNode* newnode = BuyListNode(x);
	phead->prev = newnode;
	newnode->next = phead;
	tail->next = newnode;
	newnode->prev = tail;
}
//头插
//头插在第一个有效数据前面,头节点不存储有效数据
void ListPushFront(ListNode* phead, LTDataType x)
{
    
    
	assert(phead);
	ListNode* newnode = BuyListNode(x);
	ListNode* next = phead->next;
	phead->next = newnode;
	newnode->next = next;
	next->prev = newnode;
	newnode->prev = phead;
}
//尾删
void ListPopBack(ListNode* phead)
{
    
    
	assert(phead);
	//没有数据了,只有一个头节点
	assert(phead->next != phead);
	ListNode* tailprev = phead->prev->prev;
	ListNode* tail = phead->prev;
	phead->prev = tailprev;
	tailprev->next = phead;
	free(tail);
}
//头删
void ListPopFront(ListNode* phead)
{
    
    
	assert(phead);
	//链表没有数据了,不能在删了
	assert(phead->next != phead);
	ListNode* pheadnext = phead->next;
	ListNode* next = pheadnext->next;
	phead->next = next;
	next->prev = phead;
	free(pheadnext);
}
//查找
ListNode* ListFind(ListNode* phead, LTDataType x)
{
    
    
	assert(phead);
	ListNode* cur = phead->next;
	while (cur != phead)
	{
    
    
		if (cur->data == x)
		{
    
    
			printf("找到了%d\n", cur->data);
			return cur;
		}
		else
		{
    
    
			cur = cur->next;
		}
	}
	printf("没找到%d\n", x);
	return NULL;
}
//在pos之前插入x
void ListInsert(ListNode* pos, LTDataType x)
{
    
    
	assert(pos);
	ListNode* newnode = BuyListNode(x);
	ListNode* posprev = pos->prev;
	newnode->next = pos;
	pos->prev = newnode;
	posprev->next = newnode;
	newnode->prev = posprev;
}
//删除pos位置节点
//注意这里pos不能是phead,否则就破坏了链表大结构
void ListErase(ListNode* pos)
{
    
    
	assert(pos);
	assert(pos->next != pos);
	ListNode* posprev = pos->prev;
	ListNode* posnext = pos->next;
	posprev->next = posnext;
	posnext->prev = posprev;
	free(pos);
}

(3)test.c 用于测试各项功能

#include"DoubleList.h"

int main()
{
    
    
	ListNode* phead = ListCreat();
	//尾插
	printf("尾插测试: ");
	ListPushBack(phead, 1);
	ListPushBack(phead, 2);
	ListPushBack(phead, 3);
	ListPushBack(phead, 4);
	ListPushBack(phead, 5);
	ListPrint(phead);
	//头插
	printf("头插测试: ");
	ListPushFront(phead, 0);
	ListPushFront(phead, -1);
	ListPushFront(phead, -2);
	ListPushFront(phead, -3);
	ListPushFront(phead, -4);
	ListPushFront(phead, -5);
	ListPrint(phead);
	//尾删
	printf("尾删测试: ");
	ListPopBack(phead);
	ListPrint(phead);
	//头删
	printf("头删测试: ");
	ListPopFront(phead);
	ListPrint(phead);
	//查找
	printf("查找测试: ");
	ListFind(phead, 0);
	//在pos之前插入x
	printf("找pos位置的数测试: ");
	ListNode* pos = ListFind(phead, 3);
	printf("插入x到pos位置之后的结果为: ");
	ListInsert(pos, 30);
	ListPrint(phead);
	//删除pos位置节点
	printf("找pos位置的数测试: ");
	ListNode* pos1 = ListFind(phead, 30);
	printf("删除pos位置之后的结果为: ");
	ListErase(pos1);
	ListPrint(phead);
	//链表的销毁
	ListDestory(phead);
	return 0;
}

(4)测试结果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_50886514/article/details/113815507