单链表(Linked List)
目录
说明
单链表是一种有序的列表
以节点的方式来进行存储(链式存储)
每个节点包含 data 域和 next 域
当节点没有下一个节点是,next为null
各个节点不一定连续存放
分为带头节点的和不带头节点的,根据需求来确定。
图解
节点代码
class Node
{
public int ID { get; set; }
public string Name { get; set; }
public Node Next { get; set; }
public Node(int iniID, string iniName)
{
this.ID = iniID;
this.Name = iniName;
}
public override string ToString()
{
return $"[ID: {ID}, Name: {Name}]";
}
}
[注]
此处重写了 Node 的 ToString 方法,方便打印节点信息
链表代码框架
class SingleLinkedList
{
private Node Head = new Node(0, "");
public void Add(Node newNode);
public void InsertByOrder(Node newNode);
public void Delete(int ID);
public void Update(Node newNode);
public void Find(int ID);
}
增
直接添加到链表末尾
目标
将传入的节点插入到当前链表的末尾
思路
从 Head 开始遍历,找到链表末尾,将最后一个节点的 next 指向新节点即可
代码
public void Add(Node newNode)
{
var temp = Head;
while (true)
{
if (temp.Next == null)
{
temp.Next = newNode;
break;
}
temp = temp.Next;
}
}
根据节点内某属性来按照特定顺序的添加
目标
将传入的节点插入到当前链表,并且要求链表中的节点依据ID从小到大的顺序排列
思路
[注] 本例按照ID从小到大的顺序
1.通过一个辅助变量找到待添加的位置
2.
newNode.Next = temp.Next;
temp.Next = newNode;
图解
代码
public void InsertByOrder(Node newNode)
{
var temp = Head;
bool flag = false; //用于表示当前链表中是否已经存在对应ID的节点
while (true)
{
if (temp.Next == null)
{
break;
}
if (temp.Next.ID == newNode.ID)
{
flag = true;
break;
}
else if (temp.Next.ID > newNode.ID)
{
break;
}
temp = temp.Next;
}
if (flag)
{
Console.WriteLine("当前ID已有,添加失败");
return;
}
else
{
newNode.Next = temp.Next;
temp.Next = newNode;
}
}
删
目标
传入 int 类型的 iD 值,查找对应ID值的节点,并将其从链表中删除,如果未找到则删除失败
思路
1.根据辅助变量找到待删除节点的前一节点
2. temp.next = temp.next.next;
[注] 如果辅助变量指向待删除节点的话,因为是单链表,无法访问前一节点,因此无法删除
图解
代码
public void Delete(int ID)
{
if (Head.Next == null)
{
Console.WriteLine("链表为空");
return;
}
var temp = Head;
var flag = false; //用于表示当前链表中是否已经有对应ID值的节点
while (true)
{
if (temp.Next == null)
{
break;
}
if (temp.Next.ID == ID)
{
flag = true;
break;
}
temp = temp.Next;
}
if (flag)
{
temp.Next = temp.Next.Next;
}
else
{
Console.WriteLine("未找到");
}
}
改
目标
传入一个新的节点,通过ID找到待修改的节点,将旧节点的信息替换
思路
遍历查找即可
代码
public void Update(Node newNode)
{
if (Head.Next == null)
{
Console.WriteLine("链表为空");
return;
}
var temp = Head.Next;
bool flag = false; //表示是否找到对应ID的节点
while (true)
{
if (temp == null)
{
break;
}
if (temp.ID == newNode.ID)
{
flag = true;
break;
}
temp = temp.Next;
}
if (flag)
{
temp.Name = newNode.Name;
}
else
{
Console.WriteLine("未找到对应节点");
}
}
查
目标
通过传入的ID 值找到链表中匹配的节点,并将节点返回
思路
遍历即可
代码
public Node Find(int ID)
{
if (Head.Next == null)
{
Console.WriteLine("链表为空");
return null;
}
var temp = Head.Next;
bool flag = false; //表示是否找到对应节点
while (true)
{
if (temp == null)
{
break;
}
if (temp.ID == ID)
{
flag = true;
break;
}
temp = temp.Next;
}
if (flag)
{
return temp;
}
else
{
Console.WriteLine("没找到");
return null;
}
}
完整代码
class SingleLinkedList
{
public Node Head { get; }
public SingleLinkedList()
{
this.Head = new Node(0, "");
}
public void Add(Node newNode)
{
var temp = Head;
while (true)
{
if (temp.Next == null)
{
temp.Next = newNode;
break;
}
temp = temp.Next;
}
}
public void InsertByOrder(Node newNode)
{
var temp = Head;
bool flag = false; //用于表示当前链表中是否已经存在对应ID的节点
while (true)
{
if (temp.Next == null)
{
break;
}
if (temp.Next.ID == newNode.ID)
{
flag = true;
break;
}
else if (temp.Next.ID > newNode.ID)
{
break;
}
temp = temp.Next;
}
if (flag)
{
Console.WriteLine("当前ID已有,添加失败");
return;
}
else
{
newNode.Next = temp.Next;
temp.Next = newNode;
}
}
public void Delete(int ID)
{
if (Head.Next == null)
{
Console.WriteLine("链表为空");
return;
}
var temp = Head;
var flag = false;
while (true)
{
if (temp.Next == null)
{
break;
}
if (temp.Next.ID == ID)
{
flag = true;
break;
}
temp = temp.Next;
}
if (flag)
{
temp.Next = temp.Next.Next;
}
else
{
Console.WriteLine("未找到");
}
}
public void Update(Node newNode)
{
if (Head.Next == null)
{
Console.WriteLine("链表为空");
return;
}
var temp = Head.Next;
bool flag = false;
while (true)
{
if (temp == null)
{
break;
}
if (temp.ID == newNode.ID)
{
flag = true;
break;
}
temp = temp.Next;
}
if (flag)
{
temp.Name = newNode.Name;
}
else
{
Console.WriteLine("未找到对应节点");
}
}
public Node Find(int ID)
{
if (Head.Next == null)
{
Console.WriteLine("链表为空");
return null;
}
var temp = Head.Next;
bool flag = false;
while (true)
{
if (temp == null)
{
break;
}
if (temp.ID == ID)
{
flag = true;
break;
}
temp = temp.Next;
}
if (flag)
{
return temp;
}
else
{
Console.WriteLine("没找到");
return null;
}
}
}
补充
队列反转
[注]创建一个新的头节点,遍历当前链表,使用头插法将当前链表所有节点插入新的头节点中,最后让链表头节点的 next 指向 新头节点的 next 即可。
代码
public void Reverse()
{
if (Head.Next == null || Head.Next.Next == null)
{
return;
}
var reverseHead = new Node(0, "");
var cur = Head.Next;
Node next = null;
while (cur != null)
{
next = cur.Next;
cur.Next = reverseHead.Next;
reverseHead.Next = cur;
cur = next;
}
Head.Next = reverseHead.Next;
}