数据结构--双向带头循环链表接口的实现

1 双向带头循环链表结构

双向带头循环链表的示意图如下:
在这里插入图片描述
它的定义如下:

//无头单向非循环链表的定义
typedef int LDataType ;
typedef struct ListNode {
LDataType data ;
struct ListNode* next ;
struct ListNode* prev ;
}ListNode;


typedef struct List {
struct ListNode* head;
}List;

2 无头单向非循环链表接口的实现

2.1 头文件及链表的定义

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

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

typedef struct List {
	struct ListNode* head;
}List;

2.2 创建一个新节点

//创建一个新节点
ListNode* createListNode(LDataType val) {
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	node->data = val;
	node->prev = node->next = NULL;
	return node;
}

2.3 链表的初始化

//链表的初始化
void listInit(List* lst) {
	lst->head = creatListNode(0);
	//头节点的前一个节点和后一个节点均为其自身
	lst->head->next = lst->head->prev = lst->head;
}

2.4 尾插一个数据

//尾插一个数据
void listPushBack(List* lst, LDataType val) {
	if (lst == NULL)
		return;
	//头节点的前一个节点为最后一个节点
	ListNode* node = createListNode(val);
	ListNode* last = lst->head->prev;
	//进行尾插
	last->next = node;
	node->next = lst->head;
	node->prev = last;
	lst->head->prev = node;
}

2.5 尾删一个数据

//尾删一个数据
void listPopBack(List* lst) {
	//链表不存在或者链表为空时直接返回程序
	if (lst == NULL || lst->head->next == lst->head) {
		return;
	}
	//头节点的前一个节点为最后一个节点
	ListNode* last = (ListNode*)malloc(sizeof(ListNode));
	ListNode* prev = last->prev;

	//进行尾删
	prev->next = lst->head;
	lst->head->prev = prev;
	free(last);
}

2.6 头插一个数据

//头插一个数据
void listPushFront(List* lst, LDataType val){
	if (lst == NULL)
		return;
	ListNode* node = createListNode(val);
	ListNode* next = lst->head->next;

	//进行头插
	lst->head->next = node;
	node->next = next;
	
	next->prev = node;
	node->prev = lst->head;
}

2.7 头删一个数据

//头删一个数据
void listPopFront(List* lst) {
	//链表不存在或者链表为空时直接返回程序
	if (lst == NULL || lst->head->next == lst->head) {
		return;
	}
	ListNode* node = lst->head->next;
	ListNode* next = node->next;

	//进行头删
	lst->head->next = next;
	next->prev = lst->head;
	free(node);
}

2.8 删除给定节点(不可删除头节点)

//删除给定节点(不可删除头节点)
void listErase(List* lst, ListNode* node) {
	//若链表不存在 ; 链表为空链表;节点为头节点则直接返回
	if (lst == NULL || lst->head->next == lst->head || node == lst->head)
		return;
	ListNode* prev = node->prev;
	ListNode* next = node->next;

	//进行删除
	prev->next = next;
	next->prev = prev;
	free(node);
}

2.9 在node节点位置处插入新节点

// 在node节点位置处插入新节点
void listInsert(List* lst,  ListNode* node,LDataType val) {
	//若链表不存在则返回
	if (lst == NULL)
		return;
	ListNode* prev = node->prev;
	ListNode* newNode = createListNode(val);

	//插入节点
	prev->next = newNode;
	newNode->next = node;
	node->prev = newNode;
	newNode->prev = prev;
}

2.10 查找某个节点

//查找某个节点
ListNode* listFind(List* lst, LDataType val) {
	if (lst == NULL || lst->head->next == lst->head)
		return;
	ListNode* cur = lst->head->next;
	while (cur != lst->head) {
		if (cur->data == val)
			break;
		cur = cur->next;
	}
}

2.11 求链表的长度

//求链表的长度
int listSize(List* lst) {
	if (lst == NULL || lst->head->next == lst->head)
		return 0;
	int len = 0;
	ListNode* cur = lst->head->next;
	while (cur != lst->head) {
		len++;
		cur = cur->next;
	}
	return len;
}

2.12 打印链表

//打印链表
void printList(List* lst) {
	if (lst == NULL || lst->head == NULL)
		return;
	ListNode* cur = lst->head->next;
	while (cur != lst->head) {
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

2.13 查找第n个位置的节点

//查找第n个位置的节点
ListNode* listFindByIdx(List* lst, int n) {
	if (lst == NULL || lst->head->next == lst->head)
		return;
	ListNode* cur = lst->head;
	int len = 0;
	while (len < n && cur) {
		len++;
		cur = cur->next;
	}
	return cur;
}

2.14 销毁一个链表

//销毁链表
void listDestroy(List* lst) {
	if (lst == NULL || lst->head->next == lst->head)
		return;
	ListNode* cur = lst->head->next;
	while (cur != lst->head) {
		ListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	free(lst->head);
	lst->head = NULL; 
}

3 验证链表的接口

void test() {
	List lst;
	listInit(&lst);//初始化链表
	listPushBack(&lst, 1);//尾插1
	//链表为1
	printList(&lst); //打印链表
	listPushBack(&lst, 2);//尾插2
	//链表为1->2
	printList(&lst); //打印链表
	listPushFront(&lst, 0);//头插0
	//链表为0->1->2
	printList(&lst); //打印链表

	ListNode* cur = listFind(&lst, 1);//查找值为1的节点
	listInsert(&lst, cur, 11);//在值为1的节点前的插入11
	//链表为0->11->1->2
	printList(&lst); //打印链表
	listInsert(&lst , lst.head, 13);//尾插13
	//链表为0->11->1->2->13
	printList(&lst); //打印链表

	listPopBack(&lst);//尾删
	//链表为0->11->1->2
	printList(&lst); //打印链表
	listPopFront(&lst);//头删
	//链表为11->1->2
	printList(&lst); //打印链表
	cur = listFindByIdx(&lst, 1);
	listErase(&lst , cur);//删除位置为1的节点
	//链表为1->2
	printList(&lst); //打印链表
	listErase(&lst , lst.head->prev);//尾删
	//链表为1
	printList(&lst); //打印链表
	listDestroy(&lst);//销毁链表
	printList(&lst); //打印链表

}

int main() {
	test();
	return 0;
}

运行结果如下图:
在这里插入图片描述

  • 一个小技巧
    可以将所有的全局变量及函数声明均定义在一个头文件中,这样,就不用考虑.c文件中函数的先后顺序了。
    这里头文件内容如下:
typedef int LDataType;
typedef struct ListNode {
	LDataType data;
	struct ListNode* next;
	struct ListNode* prev;
}ListNode;

typedef struct List {
	struct ListNode* head;
}List;

//链表的初始化
void listInit(List* lst);
//尾插一个数据
void listPushBack(List* lst, LDataType val);
//尾删一个数据
void listPopBack(List* lst);
//打印链表
void printList(List* lst);
//头插一个数据
void listPushFront(List* lst, LDataType val);
//头删一个数据
void listPopFront(List* lst);
//删除给定节点(不可删除头节点)
void listErase(List* lst, ListNode* node);
// 在node节点位置处插入新节点
void listInsert(List* lst, ListNode* node, LDataType val);
//查找第n个位置的节点
ListNode* listFindByIdx(List* lst, int n);
//查找某个节点
ListNode* listFind(List* lst, LDataType val);
//求链表的长度
int listSize(List* lst);
//销毁链表
void listDestroy(List* lst);
void test();

.c文件中所要声明的头文件如下:

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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值