C# 实现双向链表

双向链表

节点代码

    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;
            }
        }


    }


}

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值