C#数据结构-静态链表

闭包沙漏
• 阅读 143

对于双向链表中的节点,都包括一个向前、向后的属性器用于指向前后两个节点,对于引用类型,对象存储的是指向内存片段的内存指针,那么我们可以将其简化看作向前向后的两个指针。

现在我们将引用类型替换为值类型int,将链用数组代替,向后的指针替换为数组的下标,那么此时的链我们称为静态链表(或者说是单向静态链表)。

不多说,直接上代码(代码已做注解)

public class Node<T>
    {

        public T data { get; set; }

        public int next { get; set; }

        public Node(T item)
        {
            data = item;
        }
    } 
public class StaticLink<T>
    {
        public int count { get; set; } = 0;
        public Node<T>[] link { get; set; }
        public int minSize { get; set; } = 10;
        public int extendSize { get; set; } = 10;//扩容步长
        public StaticLink()
        {
            //第一个节点为空节点,不存储内容,同时,第一个节点的next存放备用链表的第一个节点(备用链表——数组内可以用于存储内容的处于空值时的节点连接成的表)
            //初始化,静态链表的长度为10;
            link = new Node<T>[minSize];
            for (int i = 0; i < minSize; i++)
            {
                //i=0时,由于链表为空,则备用链表的第一个节点也就是1
                link[i] = new Node<T>(default(T));
                link[i].next = i + 1;
            }
            //初始化,静态链表的结尾next 指向第一个节点(除头节点外)
            link[minSize - 1].next = 1;
            count++;
        }
        private int Malloc()
        {
            //取得静态链表-备用链表中的第一个节点(取出待用,存储内容)
            int i = link[0].next;
            if (i > 0)
            {
                //同时,移除备用链表的第一个节点,
                link[0].next = link[i].next;
                //取到链表的最后一个元素时,扩容。
                if (i >= minSize - 1)
                {
                    //todo 不翻倍扩容,采用定值步长扩容~
                    //todo 暂不实现
                }
            }
            return i;
        }
        /// <summary>
        /// 在链表的结尾附加
        /// </summary>
        /// <param name="node"></param>
        public void Append(T node)
        {
            Insert(count, node);
        }
        /// <summary>
        /// 指定位置插入节点
        /// </summary>
        /// <param name="index"></param>
        /// <param name="node"></param>
        public void Insert(int index, T node)
        {
            //要插入的节点需要在链表的范围内
            if (index > count || index < 1)
                throw new IndexOutOfRangeException("索引超出界限");
            //由于时插入节点,所以此处我们需要从备用链表取出一个空节点。
            int maxIndex = Malloc();
            int k = minSize - 1; 
            Node<T> newNode = new Node<T>(node);//创建一个节点

            if (count == 1)
                newNode.next = 0;
            else 
            {
                //取链表最后一个节点的next;
                for (int i = 1; i <= index -1; i++)
                {
                    k = link[k].next;
                }
                newNode.next = link[k].next;
                link[k].next = maxIndex;
            }
            link[maxIndex] = newNode;
            count++;
        }
        /// <summary>
        /// 根据索引删除
        /// </summary>
        /// <param name="index"></param>
        public void Del(int index)
        {
            //去除头节点,并判断索引要在链表范围内
            if (index < 1 || index > count)
                throw new IndexOutOfRangeException("索引超出界限");
            int k = minSize - 1;
            //通过链取得前一个节点 -时间复杂度O(n)
            for (int j = 1; j <= index - 1; j++)
            {
                k = link[k].next;
            }
            int beforeNodeNext = link[k].next;//获取前一个节点的next;
            link[k].next = link[beforeNodeNext].next;//跳过要删除的节点
            link[beforeNodeNext].next = link[0].next;//将释放除来的节点接入备用链
            link[0].next = beforeNodeNext;//将当前释放的节点放入到备用的第一个节点。-待用
            count--;
        }
        /// <summary>
        /// 展示链节点
        /// </summary>
        public void showAll()
        {
            for (int i = 1; i <= count; i++)
            {
                Console.WriteLine($"index:{link[i].next},data:{link[i].data}");
            }
        }
  } 

测试:

class Program
    {
        static void Main(string[] args)
        {
            StaticLink<string> link = new StaticLink<string>();
            link.Append("第一位");
            link.Append("第二位");
            link.Append("第三位");
            link.Insert(2,"第四位,插入到二的位置");
            link.Append("第五位");
            link.Append("第六位");
            link.Append("第七位");
            link.Del(6);

            link.showAll();

            Console.ReadLine();
        }
    } 

打印结果:

</span>

<span class="colour" style="color:rgb(0, 0, 0)">C#数据结构-静态链表</span>

<span class="colour" style="color:rgb(0, 0, 0)"> </span>

<span class="colour" style="color:rgb(0, 0, 0)"> </span>

点赞
收藏
评论区
推荐文章
22 22
4年前
【数据结构之链表】详细图文教你花样玩链表
【系列文章推荐阅读】0.提要钩玄文章已经介绍了链式存储结构,介绍了链式存储结构的最基本(简单)实现——单向链表。单向链表,顾名思义,它是单向的。因为单链表的每个结点只有一个数据域和一个指针域,而该指针域只存储了下一个结点的地址,所以我们只能通过某结点找到其直接后继结点,却不能通过某节点找到其直接前驱结点。此外,由于单链表到尾结点(链表的最后一
仔细看看,会有收获。js深浅拷贝
好好理解深浅拷贝和赋值(针对引用类型)赋值:两个对象指向同一内存地址。结果,无论是修改基本类型还是引用类型,两个对象的值都会改变。浅拷贝:两个对象指向不同的内存地址,但是他们中的引用类型数据指向同一内存地址。结果,修改引用类型,两个对象的值都会改变;修改基本类型,互不影响。深拷贝:两个对象指向不同的内存地址,他们中的引用类型也指向不同的内存地址。结果,均互不
似梦清欢 似梦清欢
2年前
查找算法
顺序查找顺序查找又称为线性查找,对线性表和链表都适用。线性表可以通过数组下标递增来顺序扫描每个元素,链表可以通过next指针依次扫描每一个元素。:::tip指针实现顺序表时,顺序表中是指针时,在定义顺序表的结构体后,需要对顺序表初始化,初始化时为指针申请堆
Easter79 Easter79
3年前
tbox链表list和list_entry的使用
TBOX中提供了各种列表操作:1.list:元素在内部维护的双向链表2.list\_entry:元素在外部维护的双向链表3.single\_list:元素在内部维护的单向链表4.single\_list\_entry:元素在外部维护的单向链表由于双链和单链的接口使用类似,这里主要就
Souleigh ✨ Souleigh ✨
4年前
JS 实现单链表
要存储多个元素,数组(或列表)可能是最常用的数据结构。但这种数据结构有一个缺点:(在大多数语言中)数据的大小是固定的,从数组的起点或中间插入或移除项的成本很高。  链表存储有序的集合,但不同于数组,链表中的元素在内存中并不是连续放置的。每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称指针或链接)组成。  相对于传统的数组,链表的一个好处是
Kevin501 Kevin501
4年前
Go语言中new()和make()的区别
1.Go语言中的值类型和引用类型值类型:int,float,bool,string,struct和数组(数组要特别注意,别搞混了)变量直接存储值,分配栈区的内存空间,这些变量所占据的空间在函数被调用完后会自动释放。引用类型:slice,map,chan和值类型对应的指针变量存储的是一个地址(或者理解为指针),指针指向内存中真
Stella981 Stella981
3年前
JavaScript的深拷贝和浅拷贝
一、数据类型数据分为基本数据类型(String,Number,Boolean,Null,Undefined,Symbol)和对象数据类型。、1.基本数据类型的特点:直接存储在栈(stack)中的数据2.引用数据类型的特点:存储的是该对象在栈中引用,真实的数据放在堆内存里。引用数据类型在栈中存储了指针,该指针指向堆中该实
Wesley13 Wesley13
3年前
Java实现单链表反转操作
单链表是一种常见的数据结构,由一个个节点通过指针方式连接而成,每个节点由两部分组成:一是数据域,用于存储节点数据。二是指针域,用于存储下一个节点的地址。在Java中定义如下:publicclassNode{privateObjectdata;//数据域privateNodenext;//指针域publicNo
Wesley13 Wesley13
3年前
C89和C99标准比较
1、增加restrict指针C99中增加了公适用于指针的restrict类型修饰符,它是初始访问指针所指对象的惟一途径,因此只有借助restrict指针表达式才能访问对象。restrict指针指针主要用做函数变元,或者指向由malloc()函数所分配的内存变量。restrict数据类型不改变程序的语义。如果某个函数定义了两个restrict指针变
Stella981 Stella981
3年前
Python C 扩展的引用计数问题探讨
PythonGC机制对于Python这种高级语言来说,开发者不需要自己管理和维护内存。Python采用了引用计数机制为主,标记清除和分代收集两种机制为辅的垃圾回收机制。首先,需要搞清楚变量和对象的关系:变量:通过变量指针引用对象。变量指针指向具体对象的内存空间,取对象的值。对象,类型已知,每个对象都包
菜园前端 菜园前端
2年前
什么是链表?
原文链接:什么是链表?链表是有序的数据结构,链表中的每个部分称为节点。可以首、尾、中间进行数据存取,链表的元素在内存中不必是连续的空间,每个节点通过next指针指向下一个节点。优点链表的添加和删除不会导致其余元素位移。缺点无法根据索引快速定位元素。数组和链