数据结构之双向链表--C#版

面试考察频率:⭐⭐⭐⭐

什么是双向链表?

在单向链表的前提下,增加了前驱指针,可以跟轻松的访问一个节点的前驱与后继节点

双向链表优缺点?

优点:可以更便捷的访问一个节点的前驱与后继。
缺点:需要占用更多一些的内存。删除节点操作变得更加复杂。

如何来实现?

构建思路如下
当前节点的next指向下一个节点。当前节点的pre指向上一个节点如此循环。(注:头节点的pre始终指向最后一个节点,为了方便遍历,具体的在后面会讲)。基本的样子就入下图所示(绘制粗糙0.0)

基础结构表示:

        public class LinkedListNode
        {
            public LinkedListNode pre;
            public LinkedListNode next;
            public int val;
        }

初始化:

        private void InitList(int c, LinkedListNode node)
        {
            node = new LinkedListNode();
            node.pre = node;
            node.next = null;
            node.val = -1;
        }

就是创建一个头节点,该节点不进行数据记录只是为了方便操作。初始只有一个节点时pre要指向自己。

尾插入:

public void Add_Back(LinkedListNode node, int x)
        {
            LinkedListNode tmp = node;
            while (tmp.next != null)
            {
                tmp = tmp.next;
            }
            LinkedListNode p = new LinkedListNode();
            p.next = null;
            p.pre = tmp;
            p.val = x;
 
            node.pre = p;
            tmp.next = p;
 
            m_length++;
        }

尾插入和单链表的尾插入基本相似,都要先遍历找到最后一个节点。然后记得更新头节点的pre指针,始终指向最后一个节点。

打印与反向打印:

        public void PrintList(LinkedListNode node)
        {
            LinkedListNode p = node;
            while (p.next != null)
            {
                Console.WriteLine(p.next.val);
                p = p.next;
            }
            Console.WriteLine();
        }
 
        public void ReversePrintList(LinkedListNode node)
        {
            LinkedListNode p = node.pre;
            while (p != node)
            {
                Console.WriteLine(p.val);
                p = p.pre;
            }
            Console.WriteLine();
        }

正向打印没有什么多说的,和单链表的打印一样。

反向打印从头节点开始,因为头节点的pre始终指向最后一个节点,所以也就是相当与从最后一个节点开始遍历一样,逐个走每个节点的pre域。当遍历的pre域等于头节点时表示遍历完成。

删除节点:

        public void DeleteValueAsPosition(LinkedListNode node, int pos)
        {
            LinkedListNode tNode= FindNodeAsPosition(node, pos);
            
            if(pos==Length)//如果是尾节点的情况
            {
                Console.WriteLine("删除的是尾节点");
                node.pre = tNode.pre;
                tNode.pre.next = null;
            }
            else//如果不是尾巴节点的情况
            {
                tNode.pre.next = tNode.next;
                tNode.next.pre = tNode.pre;
            }
            m_length--;
        }

需要考虑是最后一个节点还是非最后一个节点。

如果为最后一个节点要更新头节点的pre,然后取到倒数第二个节点,把next与最后一个节点断开。

如果不是最后一个节点要取得到要删除节点的上一个节点,设置其next域断开当前节点。然后取到要删除节点的下一个节点,设置其pre域断开当前节点。

完整代码如下,更多数据C#数据结构源码欢迎浏览我的仓库:https://github.com/w199753/DataStructural-CSharp 最后附上完整代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace DataStructural
{
    public class DoubleLinkedList
    {
        private int m_length = 0;
        public int Length { get { return m_length; } }
 
        public class LinkedListNode
        {
            public LinkedListNode pre;
            public LinkedListNode next;
            public int val;
        }
 
        public void CreateList(int c, LinkedListNode node)
        {
            InitList(c, node);
            for (int i = 0; i < c; i++)
            {
                int x = int.Parse(Console.ReadLine().ToString());
                Add_Back(node, x);
            }
        }
        private void InitList(int c, LinkedListNode node)
        {
 
            node = new LinkedListNode();
            node.pre = node;
            node.next = null;
            node.val = -1;
        }
 
        /// <summary>
        /// 尾插入
        /// </summary>
        /// <param name="node"></param>
        /// <param name="x"></param>
        public void Add_Back(LinkedListNode node, int x)
        {
            LinkedListNode tmp = node;
            while (tmp.next != null)
            {
                tmp = tmp.next;
            }
            LinkedListNode p = new LinkedListNode();
            p.next = null;
            p.pre = tmp;//设置新节点的pre指向最后一个节点
            p.val = x;
 
            node.pre = p;//设置头节点的pre域为新节点
            tmp.next = p;//连接新节点
 
            m_length++;
        }
 
        /// <summary>
        /// 插入元素,要判断实在尾部还是在身子部
        /// </summary>
        /// <param name="node"></param>
        /// <param name="pos"></param>
        /// <param name="x"></param>
        public void Insert(LinkedListNode node, int pos, int x)
        {
            LinkedListNode p = new LinkedListNode();
            if(pos==Length-1)
            {
                Add_Back(node, x);
            }
            else
            {
                LinkedListNode tNode = FindNodeAsPosition(node, pos);
                p.val = x;
                p.pre = tNode;
                p.next = tNode.next;
 
                tNode.next.pre = p;
                tNode.next = p;
            }
            m_length++;
        }
 
        public void PrintList(LinkedListNode node)
        {
            LinkedListNode p = node;
            while (p.next != null)
            {
                Console.WriteLine(p.next.val);
                p = p.next;
            }
            Console.WriteLine();
        }
 
        public void ReversePrintList(LinkedListNode node)
        {
            LinkedListNode p = node.pre;
            while (p != node)
            {
                Console.WriteLine(p.val);
                p = p.pre;
            }
            Console.WriteLine();
        }
 
        public LinkedListNode FindNodeAsPosition(LinkedListNode node, int pos)
        {
            LinkedListNode tNode = node;
            int tPos = 1;
            while (tNode.next != null)
            {
                if (tPos == pos)
                {
                    Console.WriteLine("value is:" + tNode.next.val);
                    return tNode.next;
                } 
                tNode = tNode.next;
                tPos++;
            }
            return null;
        }
 
        public LinkedListNode FindNodeAsValue(LinkedListNode node, int val)
        {
            LinkedListNode tNode = node;
            while (tNode.next != null)
            {
                if (tNode.next.val == val) return tNode.next;
                tNode = tNode.next;
            }
            return null;
        }
 
        public int IndexOf(LinkedListNode node,int val)
        {
            int index = -1;
            int z = 0;
            LinkedListNode tNode = node;
            while (tNode.next != null)
            {
                if (tNode.next.val == val)
                {
                    index = z;
                    return index;
                }
                tNode = tNode.next;
                z++;
            }
            return index;
        }
 
        /// <summary>
        /// 删除节点,要考虑最后一个和中间元素的情况。
        /// </summary>
        /// <param name="node"></param>
        /// <param name="pos"></param>
        public void DeleteValueAsPosition(LinkedListNode node, int pos)
        {
            LinkedListNode tNode= FindNodeAsPosition(node, pos);
            
            if(pos==Length)//如果是尾节点的情况
            {
                Console.WriteLine("删除的是尾节点");
                node.pre = tNode.pre;
                tNode.pre.next = null;
            }
            else//如果不是尾巴节点的情况
            {
                tNode.pre.next = tNode.next;
                tNode.next.pre = tNode.pre;
            }
            m_length--;
        }
 
        public void DeleteValueAsValue(LinkedListNode node,int value)
        {
            LinkedListNode tNode = FindNodeAsValue(node, value);
 
            int index = IndexOf(node, value);
 
            if (index==Length-1)//最后一个节点
            {
                node.pre = tNode.pre;
                tNode.pre.next = null;
            }
            else//不是最后一个节点
            {
                tNode.pre.next = tNode.next;
                tNode.next.pre = tNode.pre;
            }
            m_length--;
        }
 
        /// <summary>
        /// 清空所有节点
        /// </summary>
        /// <param name="node"></param>
        public void Clear(LinkedListNode node)
        {
            int len = Length;
            for (int i=1;i<=len;i++)
            {
                DeleteValueAsPosition(node, 1);
            }
        }
 
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值