双向链表
节点代码
class Node
{
public int ID { get; set; }
public string Name { get; set; }
public string NickName { get; set; }
public Node Next { get; set; }
public Node Pre { get; set; }
public Node(int iniID, string iniName, string iniNickName)
{
this.ID = iniID;
this.Name = iniName;
this.NickName = iniNickName;
}
public override string ToString()
{
return $"[ID: {ID}, Name: {Name}, NickName: {NickName}]";
}
}
双向链表与单链表相比只是多了一个指向前驱节点的pre。
单链表可参考C#实现单链表.
[注] 重写ToString 方法方便打印信息
代码框架
class DoubleLinkedList
{
public Node Head { get; }
public DoubleLinkedList()
{
this.Head = new Node(1, "", "");
}
//删除节点
public void Delete(int ID)
//修改节点内容,与单链表一样
public void Update(Node newNode)
//添加节点到双向链表的最后
public void Add(Node NewNode)
//根据ID大小插入
public void InsertByOrder(Node newNode)
//遍历双向链表
public void Display()
}
思路
遍历
与单链表一样,但是可以向前遍历。
通过一个辅助变量找到next为null的节点,即到达链表末尾
//遍历双向链表
public void Display()
{
if (Head.Next == null)
{
Console.WriteLine("链表为空");
return;
}
Node temp = Head.Next;
while (true)
{
if (temp == null)
{
break;
}
Console.WriteLine(temp.ToString());
temp = temp.Next;
}
}
直接添加到链表末尾
通过一个辅助变量遍历单链表,找到next为null的节点
temp.next = newNode;
newNode.pre = temp;
//添加节点到双向链表的最后
public void Add(Node NewNode)
{
Node temp = Head;
while (true)
{
if (temp.Next == null)
{
break;
}
temp = temp.Next;
}
//构成双向链表
temp.Next = NewNode;
NewNode.Pre = temp;
}
依据编号顺序添加
修改代码为:
temp.Next.Pre = newNode;
newNode.Next = temp.Next;
newNode.Pre = temp;
temp.Next = newNode;
判断条件与单链表中依据编号顺序添加相同,只是在进行添加时,如果待插入位置是链表的末尾,此时temp.Next.Pre 是 null, 不需要对 “null.pre” 进行修改。
//根据ID大小插入
public void InsertByOrder(Node newNode)
{
Node temp = Head;
bool flag = false;
while (true)
{
if (temp.Next == null)
{
break;
}
if (temp.Next.ID > newNode.ID)
{
break;
}
else if (temp.Next.ID == newNode.ID)
{
flag = true;
break;
}
temp = temp.Next;
}
if (flag)
{
Console.WriteLine("当前ID已存在");
}
else
{
//如果temp是链表末尾的节点,则不需要执行if语句中的内容
if (temp.Next != null)
{
temp.Next.Pre = newNode;
}
newNode.Next = temp.Next;
newNode.Pre = temp;
temp.Next = newNode;
}
}
修改
与单链表相同,用同一个bool类型的flag来表示是否找到,通过辅助变量找到待修改的节点,替换即可
//修改节点内容,与单链表一样
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;
temp.NickName = newNode.NickName;
}
else
{
Console.WriteLine("未找到对应节点");
}
}
删除
与单链表不同,双向链表可以实现“自我删除”,不需要通过待删除节点的上一节点来进行删除。
找到待删除的节点,执行接下来的代码:
temp.pre.next = temp.next;
temp.next.pre = temp.pre
需要注意的是,当待删除节点是链表的最后一个节点时,此时temp.next指向的时null,因此不需要执行temp.next.pre = temp.pre; 这一句
//删除节点
public void Delete(int ID)
{
if (Head.Next == null)
{
Console.WriteLine("链表为空");
return;
}
var temp = Head.Next;
var flag = false;
while (true)
{
if (temp == null)
{
break;
}
if (temp.ID == ID)
{
flag = true;
break;
}
temp = temp.Next;
}
if (flag)
{
temp.Pre.Next = temp.Next;
if (temp.Next != null)
{
//这里有风险,如果删除的节点是最后一个,
//会出问题,如果是最后一个节点,
//不需要执行下面的语句
temp.Next.Pre = temp.Pre;
}
}
else
{
Console.WriteLine("未找到");
}
}
完整代码(包含测试)
using System;
namespace DoubleLinkedListDemo
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("双向链表测试");
Node node1 = new Node(1, "宋江", "及时雨");
Node node2 = new Node(2, "卢俊义", "玉麒麟");
Node node3 = new Node(3, "吴用", "智多星");
Node node4 = new Node(4, "林冲", "豹子头");
DoubleLinkedList list = new DoubleLinkedList();
list.InsertByOrder(node1);
list.InsertByOrder(node2);
list.InsertByOrder(node3);
list.InsertByOrder(node4);
list.Display();
Wrap("修改");
Node newNode = new Node(4, "公孙胜", "入云龙");
list.Update(newNode);
list.Display();
Wrap("删除");
list.Delete(3);
list.Display();
}
static void Wrap(string info)
{
Console.WriteLine("\n\n\n" + info);
}
}
class Node
{
public int ID { get; set; }
public string Name { get; set; }
public string NickName { get; set; }
public Node Next { get; set; }
public Node Pre { get; set; }
public Node(int iniID, string iniName, string iniNickName)
{
this.ID = iniID;
this.Name = iniName;
this.NickName = iniNickName;
}
public override string ToString()
{
return $"[ID: {ID}, Name: {Name}, NickName: {NickName}]";
}
}
class DoubleLinkedList
{
public Node Head { get; }
public DoubleLinkedList()
{
this.Head = new Node(1, "", "");
}
//删除节点
public void Delete(int ID)
{
if (Head.Next == null)
{
Console.WriteLine("链表为空");
return;
}
var temp = Head.Next;
var flag = false;
while (true)
{
if (temp == null)
{
break;
}
if (temp.ID == ID)
{
flag = true;
break;
}
temp = temp.Next;
}
if (flag)
{
temp.Pre.Next = temp.Next;
if (temp.Next != null)
{
//这里有风险,如果删除的节点是最后一个,会出问题,如果是最后一个节点,不需要执行下面的语句
temp.Next.Pre = temp.Pre;
}
}
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;
temp.NickName = newNode.NickName;
}
else
{
Console.WriteLine("未找到对应节点");
}
}
//添加节点到双向链表的最后
public void Add(Node NewNode)
{
Node temp = Head;
while (true)
{
if (temp.Next == null)
{
break;
}
temp = temp.Next;
}
//构成双向链表
temp.Next = NewNode;
NewNode.Pre = temp;
}
//根据ID大小插入
public void InsertByOrder(Node newNode)
{
Node temp = Head;
bool flag = false;
while (true)
{
if (temp.Next == null)
{
break;
}
if (temp.Next.ID > newNode.ID)
{
break;
}
else if (temp.Next.ID == newNode.ID)
{
flag = true;
break;
}
temp = temp.Next;
}
if (flag)
{
Console.WriteLine("当前ID已存在");
}
else
{
if (temp.Next != null)
{
temp.Next.Pre = newNode;
}
newNode.Next = temp.Next;
newNode.Pre = temp;
temp.Next = newNode;
}
}
//遍历双向链表
public void Display()
{
if (Head.Next == null)
{
Console.WriteLine("链表为空");
return;
}
Node temp = Head.Next;
while (true)
{
if (temp == null)
{
break;
}
Console.WriteLine(temp.ToString());
temp = temp.Next;
}
}
}
}