双向带头链表实现

目录

[一. 逻辑结构图解](#一. 逻辑结构图解)

[1. 节点中存储的值](#1. 节点中存储的值)

2.逻辑实现

[二. 各种功能实现](#二. 各种功能实现)

[1. 创建节点函数](#1. 创建节点函数)

[2. 初始化哨兵位](#2. 初始化哨兵位)

[3. 尾插](#3. 尾插)

[4. 头插](#4. 头插)

[5. 尾删](#5. 尾删)

[6. 头删](#6. 头删)

[7. 打印链表值](#7. 打印链表值)

[8. 查找数据,返回节点地址](#8. 查找数据,返回节点地址)

[9. 指定地址后插入节点](#9. 指定地址后插入节点)

[10. 删除指定地址节点](#10. 删除指定地址节点)

[11. 销毁链表](#11. 销毁链表)

[三. 完整代码](#三. 完整代码)

[1. list.h](#1. list.h)

[2. list.c](#2. list.c)

[3. 测试](#3. 测试)


由于上一篇已经对链表的基本概念讲解完毕,这里就不过多赘述了

一. 逻辑结构图解

1. 节点中存储的值

qrev是上一个节点的地址

data是节点中存储的数据

next是下一个节点的位置

2.逻辑实现

第一个节点为哨兵位不存储数据

二. 各种功能实现

1. 创建节点函数
cpp 复制代码
ListNode* BuyListNode(DataType x)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	if (newnode == NULL)
	{
		exit(-1);
	}
	newnode->data = x;
	newnode->next = newnode->prev = newnode;
	return newnode;
}
2. 初始化哨兵位

由于需要改变哨兵位本身,所以用二级指针

之后就不用改变哨兵位了所以不用用二级指针

cpp 复制代码
void ListNodeInit(ListNode** pphead)
{
	*pphead = BuyListNode(0);
}
3. 尾插
cpp 复制代码
void ListNodePushBack(ListNode* phead, DataType x)
{
	ListNode* tail = phead->prev;
	assert(phead);
	ListNode* newnode = BuyListNode(x);
	newnode->prev = phead->prev;
	newnode->next = phead;

	tail->next = newnode;//之前的尾指向现在的尾
	phead->prev = newnode;//头的上一个改为现在的尾
}
4. 头插
cpp 复制代码
void ListNodePushFront(ListNode* head,DataType x)
{
	assert(head);
	ListNode* first = head->next;
	ListNode* newnode = BuyListNode(x);

	newnode->next = head->next;
	newnode->prev = head;

	first->prev = newnode;

	head->next = newnode;
}
5. 尾删
cpp 复制代码
void ListNodePopBack(ListNode* head)
{
	assert(head);
	ListNode* tail=head->prev;
	ListNode* newtail = tail->prev;
	head->prev = newtail;
	newtail->next = head;
	free(tail);
	tail = NULL;
}
6. 头删
cpp 复制代码
void ListNodePopFront(ListNode* head)
{
	assert(head);
	ListNode* first=head->next;
	ListNode* newfirst = first->next;
	head->next = newfirst;
	newfirst->prev = head;

	free(first);
	first = NULL;
}
7. 打印链表值
cpp 复制代码
void ListNodePrint(ListNode* phead)
{
	assert(phead);
	ListNode* tmp = phead->next;
	while (tmp!= phead)
	{
		printf("%d  ", tmp->data);
		tmp = tmp->next;
	}
}
8. 查找数据,返回节点地址
cpp 复制代码
ListNode* ListNodeFind(ListNode* head,DataType x)
{
	assert(head);
	ListNode* tmp = head->next;
	while (tmp!=head)
	{
		if (tmp->data == x)
			return tmp;
		tmp = tmp->next;
	}
	return NULL;
}
9. 指定地址后插入节点
cpp 复制代码
void ListNodeInsert(ListNode* pos, DataType x)
{
	assert(pos);
	ListNode* newnext = pos->next;
	ListNode* newnode = BuyListNode(x);

	newnode->prev = pos;
	newnode->next = newnext;
	
	pos->next = newnode;
	newnext->prev = newnode;

}
10. 删除指定地址节点
cpp 复制代码
void ListNodeErase(ListNode* pos)
{
	assert(pos);
	ListNode* posprev = pos->prev, * posnext = pos->next;
	posprev->next = posnext;
	posnext->prev = posprev;
	free(pos);
	pos = NULL;
}
11. 销毁链表
cpp 复制代码
void ListNodeDestroy(ListNode* head)
{
	assert(head);
	ListNode* cur = head->next;
	while (cur != head)
	{
		ListNode* next = cur->next;
		free(cur);
		cur = next;
	}
}

三. 完整代码

1. list.h
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int DataType;

typedef struct ListNode
{
	DataType data;
	struct SList* next;
	struct SList* prev;
}ListNode;

//初始化
void ListNodeInit(ListNode** pphead);
//尾插
void ListNodePushBack(ListNode* head, DataType x);
//打印链表
void ListNodePrint(ListNode* phead);
//头插
void ListNodePushFront(ListNode* head, DataType x);
//尾删
void ListNodePopBack(ListNode* head);
//头删
void ListNodePopFront(ListNode* head);
//查找数据
ListNode* ListNodeFind(ListNode* head, DataType x);
//指定位置后插入
void ListNodeInsert(ListNode* pos, DataType x);
//指定位置删除
void ListNodeErase(ListNode* pos);
//销毁链表
void ListNodeDestroy(ListNode* head);
2. list.c
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS h

#include"list.h"

ListNode* BuyListNode(DataType x)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	if (newnode == NULL)
	{
		exit(-1);
	}
	newnode->data = x;
	newnode->next = newnode->prev = newnode;
	return newnode;
}

void ListNodeInit(ListNode** pphead)
{
	*pphead = BuyListNode(0);
}

void ListNodePushBack(ListNode* phead, DataType x)
{
	ListNode* tail = phead->prev;
	assert(phead);
	ListNode* newnode = BuyListNode(x);
	newnode->prev = phead->prev;
	newnode->next = phead;

	tail->next = newnode;//之前的尾指向现在的尾
	phead->prev = newnode;//头的上一个改为现在的尾
}

void ListNodePrint(ListNode* phead)
{
	assert(phead);
	ListNode* tmp = phead->next;
	while (tmp!= phead)
	{
		printf("%d  ", tmp->data);
		tmp = tmp->next;
	}
}

void ListNodePushFront(ListNode* head,DataType x)
{
	assert(head);
	ListNode* first = head->next;
	ListNode* newnode = BuyListNode(x);

	newnode->next = head->next;
	newnode->prev = head;

	first->prev = newnode;

	head->next = newnode;
}

void ListNodePopBack(ListNode* head)
{
	assert(head);
	ListNode* tail=head->prev;
	ListNode* newtail = tail->prev;
	head->prev = newtail;
	newtail->next = head;
	free(tail);
	tail = NULL;
}

void ListNodePopFront(ListNode* head)
{
	assert(head);
	ListNode* first=head->next;
	ListNode* newfirst = first->next;
	head->next = newfirst;
	newfirst->prev = head;

	free(first);
	first = NULL;
}

ListNode* ListNodeFind(ListNode* head,DataType x)
{
	assert(head);
	ListNode* tmp = head->next;
	while (tmp!=head)
	{
		if (tmp->data == x)
			return tmp;
		tmp = tmp->next;
	}
	return NULL;
}

void ListNodeInsert(ListNode* pos, DataType x)
{
	assert(pos);
	ListNode* newnext = pos->next;
	ListNode* newnode = BuyListNode(x);

	newnode->prev = pos;
	newnode->next = newnext;
	
	pos->next = newnode;
	newnext->prev = newnode;

}

void ListNodeErase(ListNode* pos)
{
	assert(pos);
	ListNode* posprev = pos->prev, * posnext = pos->next;
	posprev->next = posnext;
	posnext->prev = posprev;
	free(pos);
	pos = NULL;
}

void ListNodeDestroy(ListNode* head)
{
	assert(head);
	ListNode* cur = head->next;
	while (cur != head)
	{
		ListNode* next = cur->next;
		free(cur);
		cur = next;
	}
}
3. 测试
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS h

#include"list.h"
void test()
{
	ListNode* head=NULL;
	ListNodeInit(&head);
	ListNodePushBack(head, 2);
	ListNodePushBack(head, 45);
	ListNodePushBack(head, 33);
	ListNodePushFront(head, 22);
	ListNodePushFront(head, 66);
	ListNode* find=ListNodeFind(head,33);
	ListNodeInsert(find, 666);
	ListNodePrint(head);
	printf("\n");
	//ListNodePopBack(head);
	ListNodeErase(find);
	ListNodePopFront(head);
	ListNodePrint(head);

}

int main()
{
	test();
}

感谢大家观看,希望可以帮到您

(づ ̄3 ̄)づ╭❤~

相关推荐
枫叶丹416 小时前
【HarmonyOS 6.0】ArkWeb 私有网络访问控制接口详解
开发语言·网络·华为·harmonyos
小杍随笔16 小时前
【Rust 1.95.0 正式发布!语言特性、标准库、平台支持全面升级,一文带你看完整更新】
开发语言·rust·策略模式
郝学胜-神的一滴16 小时前
ReLU激活函数全解析:从原理到实战,解锁深度学习核心激活单元
人工智能·pytorch·python·深度学习·算法
浪客川16 小时前
【百例RUST - 008】枚举
开发语言·后端·rust
AGV算法笔记16 小时前
最新感知算法论文分析:RaCFormer 如何提升雷达相机 3D 目标检测性能?
数码相机·算法·3d·自动驾驶·机器人视觉·3d目标检测·感知算法
李日灐16 小时前
<3>Linux 基础指令:从时间、查找、文本过滤到 .zip/.tgz 压缩解压与常用热键
linux·运维·服务器·开发语言·后端·面试·指令
脱氧核糖核酸__16 小时前
LeetCode热题100——54.螺旋矩阵(题解+答案+要点)
c++·算法·leetcode·矩阵
!停16 小时前
C++入门STL容器string底层剖析
开发语言·c++
lxh011316 小时前
电话号码的字母组合
java·javascript·算法