带头的双向循环链表的实现

本文档详细介绍了如何实现带头的双向循环链表,包括初始化、插入、删除、修改和查找等操作。通过示例代码展示了链表的创建、元素的增删改查以及打印链表等功能,同时提供了多种数据类型的打印和比较函数。此外,还包含了一些测试用例来验证链表操作的正确性。
摘要由CSDN通过智能技术生成

目录

概述:

初始工作

定义

 功能实现

初始化

获取新节点

头插

尾插

随即插入

头删

尾删

随机删除

修改

查找元素

打印链表

销毁

清空

判断为空

测试


概述:

要实现带头的双向循环链表,我们需要知道什么是头节点,如何循环。

首先,头节点是一个不存任何数据的节点,链表为空,也就是指此链表只有一个头节点。

其次,循环,则是指头指向尾,尾指向头,当链表尾空时,其头节点既是表头,也是表尾。

最后,双向,则是指其可以向前访问,也可以向后访问,这也说明了双向链表是由两个指针的,一个指向头,一个指向尾。

初始工作

定义

接下来我们定义一个双向循环链表,为了更方便的表示,我们对其进行再次封装

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

typedef int LNElemType;
typedef struct ListNode{
    LNElemType val;
    struct ListNode* prev;
    struct ListNode* next;
}ListNode;

typedef struct BidList{
    ListNode* head;
    size_t size;
}BidList;

考虑到数据的类型时不固定的,所以我们给出函数指针,对于不同的数据类型,由用户进行处理,我们只对基础数据类型进行处理

typedef void(*PRINT)(LNElemType* val);
typedef bool(*COMPARE)(LNElemType* src, LNElemType* des);
typedef void(*ASSIG)(LNElemType* src, LNElemType* des);

void printChar(char* val){
	printf("%c", *val);
}

void printShort(short* val){
	printf("%h", *val);
}

void printInt(int* val){
	printf("%d", *val);
}

void printLong(long* val){
	printf("%ld", *val);
}

void printfLongLong(long long* val){
	printf("%lld", *val);
}

void printFloat(float* val){
	printf("%f", *val);
}

void printDouble(double* val){
	printf("%lf", *val);
}

void printString(char** val){
	printf("%s", *val);
}
void IsEqual(LNElemType* src, LNElemType* des){
	return *src == *des;
}

void MoreThan(LNElemType* src, LNElemType* des){
	return *src < *des;
}

void LessThan(LNElemType* src, LNElemType* des){
	return *src > *des;
}

void setValue(LNElemType* src, LNElemType* des){
	*src = *des;
}

 功能实现

初始化

void BidListInit(BidList* phead)
{
	assert(phead != NULL);
	phead->head = (ListNode*)malloc(sizeof(ListNode));
	if (phead->head == NULL)
	{
		perror("Init fail");
		exit(1);
	}
	phead->head->next = phead->head;
	phead->head->prev = phead->head;
	//考虑到链表的初始数据可能会是一个结构,所以我们不为头节点赋初始值,防止发生错误
}

获取新节点

ListNode* BuyNode(){
	ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
	assert(newNode);
	return newNode;
}

头插

void BidListPushFront(BidList* phead, LNElemType val, ASSIG setValue){
	assert(phead != NULL);
	//创建节点
	ListNode* newNode = BuyNode();
	setValue(&newNode->val, &val);
	ListNode* first = phead->head->next;
	first->prev = newNode;
	newNode->next = first;
	newNode->prev = phead->head;
	phead->head->next = newNode;
	phead->size++;
}

尾插

void BidListPushBack(BidList* phead, LNElemType val, ASSIG setValue){
	assert(phead != NULL);
	ListNode* newNode = BuyNode();
	setValue(&newNode->val, &val);
	ListNode* tail = phead->head->prev;
	tail->next = newNode;
	newNode->next = phead->head;
	newNode->prev = tail;
	phead->head->prev = newNode;
	phead->size++;
}

随即插入

void BidListInert(BidList* phead, ListNode* pos, LNElemType val, ASSIG setValue){
	assert(pos != NULL);
	assert(phead != NULL);
	ListNode* newNode = BuyNode();
	setValue(&newNode->val, &val);
	ListNode* cur = pos->prev;
	cur->next = newNode;
	newNode->prev = cur;
	newNode->next = pos;
	pos->prev = newNode;
	phead->size++;
}

头删

void BidListPopFront(BidList* phead){
	assert(phead != NULL);
	if (phead->size == 0)
	{
		return;
	}
	ListNode* head = phead->head->next;
	phead->head->next = head->next;
	head->next->prev = phead->head;
	free(head);
	phead->size--;
}

尾删

void BidListPopBack(BidList* phead){
	assert(phead != NULL);
	if (phead->size == 0)
	{
		return;
	}
	ListNode* tail = phead->head->prev;
	tail->prev->next = phead->head;
	phead->head->next = tail->prev;
	free(tail);
	phead->size--;
}

随机删除

void BidListErase(BidList* phead, ListNode* pos){
	assert(pos != NULL);
	assert(phead != NULL);
	ListNode* next = pos->next;
	ListNode* prev = pos->prev;
	next->prev = prev;
	prev->next = next;
	free(pos);
	phead->size--;
}

修改

void BidListModify(BidList* phead, LNElemType src, LNElemType des, COMPARE IsEqual, ASSIG setValue){
	assert(phead != NULL);
	ListNode* p = phead->head->next;
	while (p != phead->head){
		if (IsEqual(&p->val, &src))
		{
			setValue(&p->val, &des);
			break;
		}
		p = p->next;
	}
}

查找元素

ListNode* BidListFind(BidList* phead, LNElemType val, COMPARE IsEqual){
	assert(phead);
	ListNode* p = phead->head->next;
	while (p != phead->head){
		if (IsEqual(&p->val, &val)){
			return p;
		}
		p = p->next;
	}
	return NULL;
}

打印链表

void BidListPrint(BidList* phead, PRINT print){
	assert(phead);
	ListNode* head = phead->head->next;
	printf("guard<->");
	while (head != phead->head){
		print(&head->val);
		printf("<->");
		head = head->next;
	}
	printf("guard\n");
}

销毁

void BidListDestory(BidList* phead){
	assert(phead != NULL);
	ListNode* p = phead->head->next;
	ListNode* t = p;
	while (p->next != phead->head){
		p = t->next;
		free(t);
		t = p;
	}
	free(phead->head);
	phead->head = NULL;
	phead->size = 0;
}

清空

void BidListClear(BidList* phead){
	assert(phead != NULL);
	ListNode* p = phead->head->next;
	ListNode* t = p;
	while (p->next != phead->head){
		p = t->next;
		free(t);
		t = p;
	}
	phead->head->next = phead->head;
	phead->head->prev = phead->head;
	phead->size = 0;
}

判断为空

bool BidListIsEmpty(BidList* phead)
{
	assert(phead != NULL);
	return phead->size == 0;
}

测试


void test01()
{
	BidList list;
	BidListInit(&list);
	BidListPushBack(&list, 1, setValue);
	BidListPushBack(&list, 2, setValue);
	BidListPushBack(&list, 3, setValue);
	BidListPushFront(&list, 10, setValue);
	BidListPushFront(&list, 20, setValue);
	BidListPushFront(&list, 30, setValue);

	BidListPrint(&list, printInt);

	ListNode* pos = BidListFind(&list, 2, IsEqual);

	BidListInert(&list, pos, 200, setValue);
	BidListErase(&list, pos);

	BidListModify(&list, 200, 100, IsEqual, setValue);

	BidListPrint(&list, printInt);
	
	BidListClear(&list);

	BidListPrint(&list,printInt);



	BidListPopBack(&list);


	BidListDestory(&list);
}


int main()
{

	test01();
	system("pause");
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Java实现带头双向循环链表的完整源码,供参考: ``` public class DoublyCircularLinkedList<T> { private Node<T> head; // 头节点 // 节点类 private static class Node<T> { T data; Node<T> prev; Node<T> next; Node(T data) { this.data = data; this.prev = null; this.next = null; } } // 构造函数 public DoublyCircularLinkedList() { head = new Node<>(null); head.prev = head; head.next = head; } // 在链表添加元素 public void add(T data) { Node<T> node = new Node<>(data); node.prev = head.prev; node.next = head; head.prev.next = node; head.prev = node; } // 在指定位置插入元素 public void insert(int index, T data) { Node<T> node = new Node<>(data); Node<T> p = head.next; int i = 0; while (p != head && i < index) { p = p.next; i++; } if (p == head || i > index) { throw new IndexOutOfBoundsException(); } node.prev = p.prev; node.next = p; p.prev.next = node; p.prev = node; } // 删除指定位置的元素 public void remove(int index) { Node<T> p = head.next; int i = 0; while (p != head && i < index) { p = p.next; i++; } if (p == head || i > index) { throw new IndexOutOfBoundsException(); } p.prev.next = p.next; p.next.prev = p.prev; p.prev = null; p.next = null; } // 获取指定位置的元素 public T get(int index) { Node<T> p = head.next; int i = 0; while (p != head && i < index) { p = p.next; i++; } if (p == head || i > index) { throw new IndexOutOfBoundsException(); } return p.data; } // 获取链表长度 public int size() { Node<T> p = head.next; int size = 0; while (p != head) { size++; p = p.next; } return size; } } ``` 该代码实现带头双向循环链表数据结构,支持在链表添加元素、在指定位置插入元素、删除指定位置的元素、获取指定位置的元素、获取链表长度等操作。在算法实现中,通过一个Node类来表示链表中的节点,包含数据域、前驱指针和后继指针。同时,链表的头节点也是一个Node对象,通过头节点来连接链表的首,形成双向循环链表
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值