从零开始实现链表数据结构
创作时间:
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
热门推荐
硫酸铜杀青苔的用法及注意事项
长高的最佳睡眠时间段
《甄嬛传》四大霸气智慧,教你如何成为大女主中的佼佼者!
盘点中国古代王朝那些幼年登基的皇帝们
借壳上市定义是怎样的
《史记今读》:作为“钢铁”的司马迁,是怎样炼成的?
AI智能审核如何实现
美味肥肠的家常做法:从选材到烹饪,教你轻松搞定这道经典美食
区块链技术应用在哪些领域?这些应用带来哪些改变?
交通事故逃逸的认定依据有哪些?如何避免被误判?
新生儿皮肤护理全攻略:从沐浴到特应性皮炎预防
手抖中医如何治疗
桂花飘香季,桂花的四大品种丹桂、银桂、金桂、四季桂,你分得清吗?
桂花的多重面貌:从自然观察到文化传承
一直咳咳咳,警惕是肺结核!张文宏最新发声
个体经营所得税如何合规缴款?
怀孕1-10个月,每月孕妈和宝宝有何变化?送你一份“孕期清单表”
胚胎干细胞的来源
现代科技如何改变我们对时间的理解
前端CSS实现特殊字体的四种方法
清朝与越南关系解析:为何未全面收复越南
汽车中的零重力座椅:舒适的驾驶体验
等额本息担保贷款:解析其优势与风险
多所高校研究生人数超过本科生,“本研倒挂”意味着什么?
乌云为什么是黑色的?看完涨知识了!
日本动画“系列构成”:从剧本到画面的全流程解析
如何分析 ETF 的市场流动性风险和投资策略?流动性风险对投资策略有何影响?
Excel中查找唯一值的四种方法
为什么说亚洲是人为制造的观念?
右手发麻当心这5种疾病