数据结构-—双向带头循环链表的增删查改(c语言)

链表的结构体以及函数声明

typedef int LTDataType;
typedef struct ListNode 
{
    
    
	LTDataType data;
	struct ListNode* prev;
	struct ListNode* next;
}ListNode;
//初始化
//void ListInit();
ListNode*  ListInit(ListNode* pHead);
// 创建返回链表的头结点.
ListNode* BuyListNode(LTDataType x);
// 双向链表销毁
void ListDestory(ListNode** ppHead);
//双向链表清除
void ListClear(ListNode* pHead);
// 双向链表打印
void ListPrint(ListNode* pHead);
//双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* pHead);
//双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);
//双向链表头删
void ListPopFront(ListNode* pHead);


//双向链表查找,是Insert和erase的基础
ListNode* ListFind(ListNode* pHead, LTDataType x);
//双向链表在pos位置之前插入节点
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);

链表初始化

两种方式,一种是传二级指针这样就可以直接改变它,一种是利用返回值接收

//也可以写成void ListInit(ListNode* pHead),不过在测试的时候就要传进来二级指针。因为phead要发生改变
//这里写成ListNode* 测试的时候可以传入一级指针,满足接口一致性
ListNode* ListInit(ListNode* pHead)
{
    
    
	/*ListNode* pHead = BuyListNode(0);*/
	pHead->next = pHead;
	pHead->prev = pHead;
	return pHead;
}

创建节点

ListNode* BuyListNode(LTDataType x)
{
    
    
	ListNode* node= (ListNode*)malloc(sizeof(ListNode));
	node->next= NULL;
	node->prev = NULL;
	node->data = x;
	return node;
}

查找节点

通过data来查找,如果有重复的返回第一个。这个接口可以和查找,删除进行配合

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)
{
    
    
	assert(pos);
	ListNode* posPrev = pos->prev;
	ListNode* newNode = BuyListNode(x);

	posPrev->next = newNode;
	newNode->prev = posPrev;

	newNode->next = pos;
	pos->prev = newNode;
	
}

删除节点

void ListInsert(ListNode* pos, LTDataType x)
{
    
    
	assert(pos);
	ListNode* posPrev = pos->prev;
	ListNode* newNode = BuyListNode(x);

	posPrev->next = newNode;
	newNode->prev = posPrev;

	newNode->next = pos;
	pos->prev = newNode;
	
}

尾删尾插,头删头插

两种方法,一种是直接实现,一种是利用已有接口
在这里插入图片描述

//尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
    
    
	//assert(pHead);
	//ListNode* newNode = BuyListNode(x);
	//ListNode* tail = pHead->prev;
	//tail->next = newNode;
	//newNode->prev = tail;
	这里犯了一个错误,让newNode的prev指向了头
	//pHead->prev = newNode;
	//newNode->next = pHead;
	//Insert代表在所选位置之前插入,这样ListInsert(pHead->prev, x);插入到倒数第二个去了
	ListInsert(pHead, x);
	

}
//尾删
void ListPopBack(ListNode* pHead)
{
    
    
	//assert(pHead);
	//assert(pHead->next != pHead);
	//ListNode* tail = pHead->prev;
	//ListNode* tailPrev = tail->prev;
	///*printf("%d %d", tail->data, tailPrev->data);*/
	//tailPrev->next = pHead;
	//pHead->prev = tailPrev;
	//free(tail);
	ListErase(pHead->prev);
}
//头插
void ListPushFront(ListNode* pHead, LTDataType x)
{
    
    
	/*assert(pHead);
	ListNode* Next = pHead->next;
	ListNode* newNode = BuyListNode(x);
	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* second =next->next;
	pHead->next = second;
	second->prev = pHead;
	free(next);*/
	ListErase(pHead->next);
}

完整代码链接:
双向带头循环链表的实现

猜你喜欢

转载自blog.csdn.net/qq_45928272/article/details/112845226