从零实现数据结构第三集:带头双向循环链表实现

第三集喽!

依旧还是声明部分list.h:

需要注意的是我们不能再结构体里面使用重命名node,只能使用全称,这是因为编译器在当前上下文中并不知道 node 是什么类型,重命名宏类似的也会在预编译阶段被替换成全称

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

typedef int ListDataType;
typedef struct ListNode
{
    struct ListNode* prev;  // 前一个指针,使用 struct ListNode*
    struct ListNode* next;  // 后一个指针,使用 struct ListNode*
    ListDataType data;      // 数据域
} node;  
// 函数声明
void ListInit(node* guard);
void ListDestroy(node* guard);
void ListPrint(node* guard);
void ListPushBack(node* guard, ListDataType x);
node* ListFind(node* guard, ListDataType x);
void ListInsert(node* pos, ListDataType x);
void ListPopFront(node* guard);
void ListPopBack(node* guard);
void ListErase(node* pos);

函数实现部分list.c:

今天的函数实现和昨天第二集很相似所以注释少了些许

初始化函数:

void ListInit(node* guard)
{
	guard->data = -1;  // 哨兵节点的数据,通常是无效数据
	guard->next = guard;  // 循环链表的哨兵节点,指向自己
	guard->prev = guard;
}

添加节点函数:

void ListDestroy(node* guard)
{
	assert(guard);
	node* cur = guard->next;
	while (cur != guard)
	{
		node* next = cur->next;  // 先保存下一个节点的指针
		free(cur);  // 释放当前节点
		cur = next;  // 移动到下一个节点
	}
	// 最后释放哨兵节点
	free(guard);
}

打印函数:

void ListPrint(node* guard)
{
	assert(guard);
	//和删除逻辑一样
	node* cur = guard->next;
	while (cur != guard)
	{
		printf("%d", cur->data);
		cur = cur->next;
	}
}

添加节点函数:

void ListDestroy(node* guard)
{
	assert(guard);
	node* cur = guard->next;
	while (cur != guard)
	{
		node* next = cur->next;  // 先保存下一个节点的指针
		free(cur);  // 释放当前节点
		cur = next;  // 移动到下一个节点
	}
	// 最后释放哨兵节点
	free(guard);
}

销毁函数:

node* AddNode(ListDataType x)
{
	node* newnode = (node*)malloc(sizeof(node));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	newnode->data = x;
	newnode->prev = NULL;
	newnode->next = NULL;
	return newnode;
}

尾插函数:

void ListPushBack(node* guard, ListDataType x)
{
	assert(guard);
	node* newnode = AddNode(x);
	node* tail = guard->prev;
	//新节点和头节点进行双向链接
	newnode->next = guard;
	guard->prev = newnode;
	//和尾节点双向链接
	tail->next = newnode;
	newnode->prev = tail;
}

查找函数:

node* ListFind(node* guard, ListDataType x)
{
	assert(guard);
	node* cur = guard->next;
	while (cur != guard)
	{
		if (cur->data == x)
			return cur;
		cur = cur->next;
	}
	return NULL;
}

插入函数:

void ListInsert(node* pos, ListDataType x)
{
	assert(pos);
	node* before = pos->prev;
	node* newnode = AddNode(x);
	//和前面节点进行双向链接
	before->next = newnode;
	newnode->prev = before;
	//和后面节点进行双向链接
	newnode->next = pos;
	pos->prev = newnode;
}

尾删函数:

void ListPopFront(node* guard)
{
	assert(guard);
	assert(guard->next != guard);//确保不是只有哨兵节点
	node* front = guard->next;
	node* newfront = front->next;
	guard->next = newfront;
	newfront->prev = guard;
	free(front);
}

头删函数:

void ListPopBack(node* guard)
{
	assert(guard);
	//判断是否为空
	assert(guard->next != guard);
	node* tail = guard->prev;
	node* newtail = tail->prev;
	newtail->next = guard;
	guard->prev = newtail;
	free(tail);
}

消除函数:

void ListErase(node* pos)
{
	assert(pos);
	node* before = pos->prev;
	node* after = pos->next;
	before->next = after;
	after->prev = before;
	free(pos);
}

全体实现代码:

#define _CRT_SECURE_NO_WARNINGS
#include "list.h"
#include <assert.h>


node* AddNode(ListDataType x)
{
	node* newnode = (node*)malloc(sizeof(node));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	newnode->data = x;
	newnode->prev = NULL;
	newnode->next = NULL;
	return newnode;
}

void ListInit(node* guard)
{
	guard->data = -1;  // 哨兵节点的数据,通常是无效数据
	guard->next = guard;  // 循环链表的哨兵节点,指向自己
	guard->prev = guard;
}

void ListDestroy(node* guard)
{
	assert(guard);
	node* cur = guard->next;
	while (cur != guard)
	{
		node* next = cur->next;  // 先保存下一个节点的指针
		free(cur);  // 释放当前节点
		cur = next;  // 移动到下一个节点
	}
	// 最后释放哨兵节点
	free(guard);
}


void ListPrint(node* guard)
{
	assert(guard);
	//和删除逻辑一样
	node* cur = guard->next;
	while (cur != guard)
	{
		printf("%d", cur->data);
		cur = cur->next;
	}
}

void ListPushBack(node* guard, ListDataType x)
{
	assert(guard);
	node* newnode = AddNode(x);
	node* tail = guard->prev;
	//新节点和头节点进行双向链接
	newnode->next = guard;
	guard->prev = newnode;
	//和尾节点双向链接
	tail->next = newnode;
	newnode->prev = tail;
}

node* ListFind(node* guard, ListDataType x)
{
	assert(guard);
	node* cur = guard->next;
	while (cur != guard)
	{
		if (cur->data == x)
			return cur;
		cur = cur->next;
	}
	return NULL;
}

void ListInsert(node* pos, ListDataType x)
{
	assert(pos);
	node* before = pos->prev;
	node* newnode = AddNode(x);
	//和前面节点进行双向链接
	before->next = newnode;
	newnode->prev = before;
	//和后面节点进行双向链接
	newnode->next = pos;
	pos->prev = newnode;
}

void ListPopFront(node* guard)
{
	assert(guard);
	assert(guard->next != guard);//确保不是只有哨兵节点
	node* front = guard->next;
	node* newfront = front->next;
	guard->next = newfront;
	newfront->prev = guard;
	free(front);
}

void ListPopBack(node* guard)
{
	assert(guard);
	//判断是否为空
	assert(guard->next != guard);
	node* tail = guard->prev;
	node* newtail = tail->prev;
	newtail->next = guard;
	guard->prev = newtail;
	free(tail);
}

void ListErase(node* pos)
{
	assert(pos);
	node* before = pos->prev;
	node* after = pos->next;
	before->next = after;
	after->prev = before;
	free(pos);
}

测试部分:

#define _CRT_SECURE_NO_WARNINGS
#include "list.h"

int main()
{
	node guard;
	ListInit(&guard);
	ListPushBack(&guard, 1);
	ListPushBack(&guard, 2);
	ListPushBack(&guard, 3);
	ListPushBack(&guard, 4);
	ListPopBack(&guard);
	ListPrint(&guard);
	ListDestroy(&guard);

	return 0;
}

感谢看到这里,谢谢┗|`O′|┛ 嗷~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值