C# 单链表 | 双链表 | 循环链表的原理和代码实现

本文介绍了链表的基本概念,包括单链表、双向链表和循环链表,并提供了C#语言的单链表和双链表的代码实现,强调了链表在内存管理和操作效率上的优势。同时,文章包含了一个简单的循环单链表的代码示例,帮助读者更好地理解链表的结构和操作。

说明:C#有自己封装的双向循环链表LinkedList<>,足以满足日常工作需要。这里只是学习数据结构“单链表”的手搓代码,理解精神即可。

PS:这篇文章第一版写的有点烂,这是第二版,好看点。

PSS: 本文的重点代码代码代码!而不是数据结构的一些基础概念和分类;
完全没接触过的同学,可以去看B站王卓教授的视频。


1.什么是链表?

  • 用一组物理位置任意的存储单元来存放线性表的数据元素。
  • 存储单元可以是连续的,也可以是不连续的,甚至是零散分布在内存中
  • 链表中元素的逻辑次序和物理次序不一定相同。(即内存靠前的不一定逻辑次序靠前)

说明:

  1. 如图,链表第一个元素是0031,即“赵”,赵的下一个是0007,即“钱”,钱的下一个是0013,即“孙”,依此类推。
  2. 物理上这些地址连续吗?很明显,不连续
  3. 物理次序和逻辑次序有关系嘛?很明显,没关系。赵是第一个,物理地址却在其他元素的下面。

2.为什么使用链表?

  • 对比顺序表(例如数组),链表没有容量上限,可以无限扩容(不考虑内存的情况下)。而数组在初始化时便敲定了最大容量,无法扩容。
  • 已知某结点的情况下,删除、插入的时间复杂度为O(1),效率同比顺序表非常高。
  • 也就是说,对于某些情况下使用链表会带来更高的效率,那为什么不用呢?

3.链表有哪几种?

  • 单(向)链表
  • 双(向)链表
  • 循环链表

4.什么是“单向”链表?

  • 每个结点只有下一个结点的指针域,则由这类结点构成的链表叫单向链表。
  • 就是说: 你通过当前结点,只能向一个方向去找下一个结点,你找不到上一个,所以叫“单向”。

说明: 比如说你有a2的引用,你可以拿到a3,但你拿不到a1。


5.什么是“双向”链表?

  • 每个结点除了保留下一个结点的指针域外,还保留了上一个结点的指针域
  • 就是说:你通过当前结点,不仅可以拿到下一个结点,也能拿到上一个结点,你可以在前后两个方向获取元素,所以叫“双向”。

说明: 比如说你有a2的引用,你可以拿到a3,而且你也能拿到a1


6.什么是“循环”链表?

  • 循环链表的概念与“单、双”链表并非互斥关系,反而可以相互包容
  • 例如: 你可以实现 循环单链表 or 循环双链表
  • 那么,为什么叫“循环”呢? 因为,最后一个结点的Next指针一般是空的,因为的确没有结点了嘛,但是你的Next指针指向第一个元素,形成了一个环状结构。
    循环单链表
    循环双链表

7.单链表代码实现

namespace YoyoCode
{
   
   
    internal class SinglyLinkedList<T>
    {
   
   
        //首元结点
        public SinglyLinkedListNode<T> First;
        //尾结点
        public SinglyLinkedListNode<T> Last;
        //结点数量
        public int NodeCount = 0;

        /// <summary>
        /// 是否为空
        /// </summary>
        /// <returns>bool,链表是否为空</returns>
        public bool IsEmpty()
        {
   
   
            return NodeCount == 0 ? true : false;
        }

        /// <summary>
        /// 清空链表
        /// </summary>
        public void Clear()
        {
   
   
            First = null;
            Last = null;
            NodeCount = 0;
        }

        /// <summary>
        /// 头插法
        /// </summary>
        /// <param name="value">类型为T的值</param>
        public void AddFirst(T value)
        {
   
   
            SinglyLinkedListNode<T> node = new SinglyLinkedListNode<T>(value);
            if (IsEmpty())
            {
   
   
                First = node;
                Last = node;
            }
            else
            {
   
   
                node.Next= First;
                First= node;
            }
            NodeCount++;
        }

        /// <summary>
        /// 尾插法
        /// </summary>
        /// <param name="value">类型为T的值</param>
        public void AddLast(T value)
        {
   
   
            SinglyLinkedListNode<T> node = new SinglyLinkedListNode<T>(value);
            if (IsEmpty())
            {
   
   
                First = node;
                Last = node;
            }
            else
            {
   
   
                Last.Next = node;
                Last = node;
            }
            NodeCount++;
        }
        /// <summary>
        /// 在对应的索引插入元素
        /// </summary>
        /// <param name="idx">索引,从0开始</param>
        public bool AddAt(T value, int idx)
        {
   
   
            if (idx < 0 || idx > NodeCount)
            {
   
   
                return false;
            }
            if (idx == 0)
            {
   
   
                AddFirst(value);
                return true;
            }
            if (idx == NodeCount)
            {
   
   
                AddLast(value);
                return true;
            }
            //其他情况
            SinglyLinkedListNode<T> prev = First;
            SinglyLinkedListNode<T> cur = First.Next;
            SinglyLinkedListNode<T> node = new SinglyLinkedListNode<T>(
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值