从零开始实现链表数据结构
创作时间:
2025-01-22 00:29:14
作者:
@小白创作中心
从零开始实现链表数据结构
链表是计算机科学中一种重要的数据结构,广泛应用于各种编程场景。本文将从链表的基本概念出发,详细讲解链表的定义、分类,并通过实际代码演示链表的实现过程,包括初始化、插入、查找、更新、删除等操作。
一、链表的定义
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列节点组成,每个节点包含两部分:数据域和指针域。数据域用于存储数据元素,指针域用于存储下一个节点的地址。
- 节点:链表的基本组成单位,包含数据域和指针域。
- 头指针:指向链表第一个节点的指针。
- 头节点:链表的第一个节点,数据域可以为空,主要用于简化链表操作。
- 首元节点:链表中第一个数据域不为空的节点。
二、链表的分类
链表主要可以分为以下几类:
- 静态链表和动态链表:根据内存分配方式区分。
- 单向链表、双向链表和循环链表:根据节点连接方式区分。
单链表:每个节点包含一个指向下一个节点的指针。
双向链表:每个节点包含两个指针,分别指向前后两个节点。
循环链表:链表首尾相连,形成闭环。可以是单向循环链表或双向循环链表。
三、链表的实现
下面将通过代码实现一个简单的单链表。我们将使用C#语言,通过手动管理内存来实现链表的基本操作。
1. ADT定义
首先定义链表的抽象数据类型(ADT):
ADT LinkedList{
数据对象:D 是一个非空的元素集合,D = {a1, a2, ..., an},其中 ai 表示一个元素即节点,一个节点存储着数据和指向下一个节点的指针。
数据关系:D中的节点通过指针进行连接,每一个节点都包含一个指向下一个节点的指针。
基本操作:[
Init(n) :初始化一个空链表,即声明一个头指针,如有必要也可以声明一个头节点。
Length:返回链表长度。
HeadNode:返回头节点。
Find(v):返回数据域v对应的节点。
Update(n,v):更新n节点的数据域。
InsertAfter(n,v):在n节点后面添加数据域为v的新节点。
Remove(n):移除n节点。
Destroy():销毁链表。
]
}
2. 定义类
定义节点结构体:
public struct MyselfLinkedListNode
{
//数据域
public string Data { get; set; }
//指针域
public IntPtr Next { get; set; }
}
定义链表实现类:
public sealed class MyselfLinkedList : IDisposable
{
//申请内存起始位置指针
private IntPtr _head;
//链表长度
private int _length;
}
3. 初始化链表
public MyselfLinkedListNode Init()
{
var size = Marshal.SizeOf(typeof(MyselfLinkedListNode));
_head = Marshal.AllocHGlobal(size);
var node = new MyselfLinkedListNode
{
Data = null,
Next = IntPtr.Zero
};
Marshal.StructureToPtr(node, _head, false);
_length++;
return node;
}
4. 获取链表长度
public int Length
{
get
{
return _length;
}
}
5. 获取头节点
public MyselfLinkedListNode? HeadNode
{
get
{
if (_head == IntPtr.Zero)
{
return null;
}
return GetNode(_head);
}
}
private MyselfLinkedListNode GetNode(IntPtr pointer)
{
return Marshal.PtrToStructure<MyselfLinkedListNode>(pointer);
}
6. 插入节点
public MyselfLinkedListNode InsertAfter(MyselfLinkedListNode node, string value)
{
var pointer = GetPointer(node);
if (pointer != IntPtr.Zero)
{
var (newPointer, newNode) = CreateNode(value);
newNode.Next = node.Next;
node.Next = newPointer;
Marshal.StructureToPtr(newNode, newPointer, false);
Marshal.StructureToPtr(node, pointer, false);
_length++;
return newNode;
}
return default;
}
private IntPtr GetPointer(MyselfLinkedListNode node)
{
var currentPointer = _head;
while (currentPointer != IntPtr.Zero)
{
var currentNode = GetNode(currentPointer);
if (currentNode.Data == node.Data && currentNode.Next == node.Next)
{
return currentPointer;
}
currentPointer = currentNode.Next;
}
return IntPtr.Zero;
}
private (IntPtr Pointer, MyselfLinkedListNode Node) CreateNode(string value)
{
var size = Marshal.SizeOf(typeof(MyselfLinkedListNode));
var pointer = Marshal.AllocHGlobal(size);
var node = new MyselfLinkedListNode
{
Data = value,
Next = IntPtr.Zero
};
Marshal.StructureToPtr(node, pointer, false);
return (pointer, node);
}
7. 查找节点
public MyselfLinkedListNode Find(string value)
{
var pointer = _head;
while (pointer != IntPtr.Zero)
{
var node = GetNode(pointer);
if (node.Data == value)
{
return node;
}
pointer = node.Next;
}
return default;
}
8. 更新节点
public void Update(MyselfLinkedListNode node, string value)
{
var pointer = GetPointer(node);
if (pointer != IntPtr.Zero)
{
node.Data = value;
Marshal.StructureToPtr(node, pointer, false);
}
}
9. 删除节点
public void Remove(MyselfLinkedListNode node)
{
var currentPointer = _head;
var currentNode = GetNode(_head);
var pointer = GetPointer(node);
while (true)
{
if (currentNode.Next == IntPtr.Zero)
{
return;
}
else if (currentNode.Next == pointer)
{
currentNode.Next = node.Next;
Marshal.FreeHGlobal(pointer);
Marshal.StructureToPtr(currentNode, currentPointer, false);
_length--;
break;
}
else
{
currentPointer = currentNode.Next;
currentNode = GetNode(currentPointer);
}
}
}
10. 销毁链表
public void Destroy()
{
var pointer = _head;
while (pointer != IntPtr.Zero)
{
var value = GetNode(pointer);
Marshal.FreeHGlobal(pointer);
_length--;
pointer = value.Next;
}
_head = IntPtr.Zero;
}
11. 释放内存
由于实现了IDisposable接口,需要在Dispose方法中调用上面的Destroy方法。
注:完整的测试代码和示例源码可以参考以下仓库:https://gitee.com/hugogoos/Planner
热门推荐
培训会议的标配:高效签到表模板设计
简历上的重点内容
公司注销时账务如何清理?一文详解账务处理、凭证保存与法律风险
固定资产责任归属不明确,部门的固定资产都存在哪些问题?
甘肃:深入推进黄河流域产业绿色发展 奋力书写新时代“黄河故事”
使用RDP文件登录Windows云服务器
品味酱香型白酒:如何选择与搭配美食
深入理解Reactor核心概念
从《延禧攻略》到《墨雨云间》,观众还是没实现“爽剧自由”
阑尾炎手术几天可以出院
养斑鸠犯法吗?一文读懂养殖斑鸠的法律法规
斑鸠是几级保护动物?了解斑鸠的保护级别
警惕心理疾病的社交传染!多种方式提升心理免疫力
走进武夷岩茶核心山场:牛栏坑的传奇与魅力
古代没有女捕快,但它的问题不在于此
喝酒后身上变红的原因是什么
抗压能力怎么提升最快
身体肥胖与左旋肉碱:原研左卡尼汀的角色与影响
中外驰名的八达岭长城
八年特斯拉用车成本详解:省钱真的只是表面现象?
路亚黑鱼用几号曲柄钩?
沙漠里种水稻!靠的是什么黑科技?
蒙脱石散可以随意吃?吃蒙脱石散要牢记这3大注意事项
军医大学毕业后的去向和待遇,军医大学的学生都有军籍吗?
男人睡觉的正确睡姿
K维树(KD - Tree)
如何合理合法书写劳动合同到期后的辞职申请
员工离职流程中的关键节点有哪些?
浙江省位于中国的哪个方向?
如何组建科研团队计划