数据结构 表(三)带头双向循环链表

上一节里实现的是最简单的链表,在实际中那种链表不会单独用来存储数据,更多是作为其他数据结构的子结构,如图的邻接表等。而比较常用的就是带头双向循环链表。
在这里插入图片描述
在这里插入图片描述
通过对比我们可以看出有三个不同,多了头节点,链表中的元素之间不再是单向而是双向,头尾节点相连,构成循环链表。
虽然结构比起之前的复杂了一点,但是优势却十分明显。
如普通链表要访问最后的元素时,只能通过遍历链表来取得,而这个可以直接取头节点的前一个来找到尾巴。链表之间是双向的,所有可以实现回溯等操作。多了头节点可以直接在头节点上对链表就行修改,不需要再使用二级指针等

数据结构
typedef struct ListNode
{
	DATATYPE data;
	struct ListNode* next;
	struct ListNode* prev;
}ListNode;

我们需要用到两个指针,一个指向当前位置的前面,一个指向后面

实现的接口
// 创建返回链表的头结点.
ListNode* ListCreate();
// 双向链表销毁
void ListDestory(ListNode* list);
// 双向链表打印
void ListPrint(ListNode* list);
// 双向链表尾插
void ListPushBack(ListNode* list, DATATYPE x);
// 双向链表尾删
void ListPopBack(ListNode* list);
// 双向链表头插
void ListPushFront(ListNode* list, DATATYPE x);
// 双向链表头删
void ListPopFront(ListNode* list);
// 双向链表查找
ListNode* ListFind(ListNode* list, DATATYPE x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, DATATYPE x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);

创建返回链表的头结点

ListNode* ListCreate()
{
	ListNode* head = (ListNode*)malloc(sizeof(ListNode));
	head->data = 0;
	head->next = head;
	head->prev = head;
	return head;
}

我们首先要创建头节点
在这里插入图片描述
在一开始我们就要确保双向循环,所以前后指针都指向自己

在pos的前面进行插入

我先不讲头插和尾插,而是直接讲插入,因为当我们能实现在pos位置插入时,就可以通过这个函数来实现头插和尾插

在这里插入图片描述
在这里插入图片描述
如图,如果我们要让他在pos前面插入,就必须先让cur处理好他与pos的prev的关系,因为如果我们先让他变成pos的前一个,那么原本的前一个节点的位置就会丢失,所以我们必须要注意好顺序

void ListInsert(ListNode* pos, DATATYPE x)
{
	assert(pos);

	ListNode* cur = (ListNode*)malloc(sizeof(ListNode));
	cur->data = x;

	pos->prev->next = cur;
	cur->prev = pos->prev;
	cur->next = pos;
	pos->prev = cur;

	
}

头插

void ListPushFront(ListNode* list, DATATYPE x)
{
	assert(list);

	ListNode* head = list;
	ListNode* tail = head->prev;
	ListNode* cur = (ListNode*)malloc(sizeof(ListNode));
	cur->data = x;

	cur->next = head->next;
	head->next->prev = cur;
	
	head->next = cur;
	cur->prev = head;
	
	//ListInsert(list->next, x);
}

这里的实现思路一样,要处理好head的下一个节点与cur的关系,我们也可以用刚刚的插入函数直接实现,插入的位置就是头节点的下一个位置

尾插

void ListPushBack(ListNode* list, DATATYPE x)
{
	assert(list);

	ListNode* head = list;
	ListNode* tail = head->prev;
	ListNode* cur = (ListNode*)malloc(sizeof(ListNode));
	cur->data = x;

	cur->prev = tail;
	cur->next = head;
	tail->next = cur;
	head->prev = cur;

	//ListInsert(list, x);
}

这里与前两个一样,就不罗嗦了,这里也可以用之前的函数,插入位置就是list也就是头节点,头节点的前一个位置就是尾节点,在这插入就是尾插

删除pos位置的节点

删除的操作和插入的思路基本一样,就不多说了

void ListErase(ListNode* pos)
{
	assert(pos);

	pos->next->prev = pos->prev;
	pos->prev->next = pos->next;
	free(pos);
}

头删

void ListPopFront(ListNode* list)
{
	assert(list);
	ListNode* head = list;
	ListNode* next = head->next;
	next->next->prev = head;
	head->next = next->next;
	free(next);
	//ListErase(list->next);
}

尾删

void ListPopBack(ListNode* list)
{
	assert(list);
	ListNode* head = list;
	ListNode* tail = list->prev;

	head->prev = tail->prev;
	tail->prev->next = head;
	free(tail);
	//ListErase(list->prev);
}

打印链表

遍历输出即可

void ListPrint(ListNode* list)
{
	assert(list);
	ListNode* cur = list->next;
	while (cur != list)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

查找链表

ListNode* ListFind(ListNode* list, DATATYPE x)
{
	assert(list);
	ListNode* cur = list->next;

	while (cur != list)
	{
		if (cur->data == x)
			return cur;
		else
			cur = cur->next;
	}

	return NULL;
}

销毁链表

void ListDestory(ListNode* list)
{
	assert(list);
	
	ListNode* head = list;
	ListNode* cur = list->next;

	while (cur != head)
	{
		ListNode* next = cur->next;
		free(cur);
		cur = next;
	}

	free(head);
	head = NULL;

}

在这里插入图片描述
完整代码
头文件

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#define _CRT_SECURE_NO_WARNINGS
#define LISTSIZE 10

typedef int DATATYPE;

typedef struct ListNode
{
	DATATYPE data;
	struct ListNode* next;
	struct ListNode* prev;
}ListNode;

// 创建返回链表的头结点.
ListNode* ListCreate();
// 双向链表销毁
void ListDestory(ListNode* list);
// 双向链表打印
void ListPrint(ListNode* list);
// 双向链表尾插
void ListPushBack(ListNode* list, DATATYPE x);
// 双向链表尾删
void ListPopBack(ListNode* list);
// 双向链表头插
void ListPushFront(ListNode* list, DATATYPE x);
// 双向链表头删
void ListPopFront(ListNode* list);
// 双向链表查找
ListNode* ListFind(ListNode* list, DATATYPE x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, DATATYPE x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);

函数实现

#include "Double-linked circular list.h"

ListNode* ListCreate()
{
	ListNode* head = (ListNode*)malloc(sizeof(ListNode));
	head->data = 0;
	head->next = head;
	head->prev = head;
	return head;
}

void ListPrint(ListNode* list)
{
	assert(list);
	ListNode* cur = list->next;
	while (cur != list)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

void ListPushBack(ListNode* list, DATATYPE x)
{
	assert(list);

	ListNode* head = list;
	ListNode* tail = head->prev;
	ListNode* cur = (ListNode*)malloc(sizeof(ListNode));
	cur->data = x;

	cur->prev = tail;
	cur->next = head;
	tail->next = cur;
	head->prev = cur;

	//ListInsert(list, x);
}

void ListPushFront(ListNode* list, DATATYPE x)
{
	assert(list);

	ListNode* head = list;
	ListNode* tail = head->prev;
	ListNode* cur = (ListNode*)malloc(sizeof(ListNode));
	cur->data = x;

	cur->next = head->next;
	head->next->prev = cur;
	
	head->next = cur;
	cur->prev = head;
	
	//ListInsert(list->next, x);
}

void ListDestory(ListNode* list)
{
	assert(list);
	
	ListNode* head = list;
	ListNode* cur = list->next;

	while (cur != head)
	{
		ListNode* next = cur->next;
		free(cur);
		cur = next;
	}

	free(head);
	head = NULL;

}

ListNode* ListFind(ListNode* list, DATATYPE x)
{
	assert(list);
	ListNode* cur = list->next;

	while (cur != list)
	{
		if (cur->data == x)
			return cur;
		else
			cur = cur->next;
	}

	return NULL;
}

void ListInsert(ListNode* pos, DATATYPE x)
{
	assert(pos);

	ListNode* cur = (ListNode*)malloc(sizeof(ListNode));
	cur->data = x;

	pos->prev->next = cur;
	cur->prev = pos->prev;
	cur->next = pos;
	pos->prev = cur;

	
}

void ListErase(ListNode* pos)
{
	assert(pos);

	pos->next->prev = pos->prev;
	pos->prev->next = pos->next;
	free(pos);
}

void ListPopBack(ListNode* list)
{
	assert(list);
	ListNode* head = list;
	ListNode* tail = list->prev;

	head->prev = tail->prev;
	tail->prev->next = head;
	free(tail);
	//ListErase(list->prev);
}

void ListPopFront(ListNode* list)
{
	assert(list);
	ListNode* head = list;
	ListNode* next = head->next;
	next->next->prev = head;
	head->next = next->next;
	free(next);
	//ListErase(list->next);
}
发布了60 篇原创文章 · 获赞 78 · 访问量 6322

猜你喜欢

转载自blog.csdn.net/qq_35423154/article/details/104296946