数据结构(2):链表

来源:互联网 发布:制造杀人犯主人公 知乎 编辑:程序博客网 时间:2024/06/05 20:37

在上一篇文章中,实现线性表中的顺序表,对于插入、删除操作比较频繁的数据来说,用顺序表就不是很经济了,这时候链表就排上用场
在C#中,直接使用指针来进行操作是比较麻烦的,不过引用可以在相当程度上代替指针,这也是C#中实现链表最简单的方法。
首先,使用引用来实现链表,通过两个类来实现的,一个事节点类,一个是链表类。主要实现了向末尾添加节点、指定位置插入节点、删除节点这些操作。

  class RefNode<T>  //节点类    {        public T data;        public RefNode<T> Next;                public RefNode()        {            data = default(T);            Next = null;        }        public RefNode(T dt)        {            data = dt;            Next = null;        }    }     class RefLinkList<T>    {        RefNode<T> HeadNode;        public int Length;        public RefLinkList()        {            HeadNode = new RefNode<T>();        }        public void Add(RefNode<T> data)    //在末尾添加节点        {            Length++;                      if (HeadNode.Next == null)          //若链表为空            {                HeadNode.Next = new RefNode<T>();                HeadNode.Next = data;                     }            else            {                var p = HeadNode.Next;                while (p.Next != null)                {                    p = p.Next;                }                p.Next = new RefNode<T>();                p.Next = data;            }        }        public bool Get(int index, out RefNode<T> tp)  //获取指定序号的节点        {            if(index > Length || index < 0)                         //若序号超出范围            {                Console.WriteLine("序号超出范围!");                tp = null;                return false;            }            var p = HeadNode;            for(int i = 0; i < index; i++)            {                p = p.Next;            }            tp = p;            return true;        }        public bool Insert(int index, RefNode<T> node)//在指定位置插入节点        {            if(index > Length || index <= 0)            {                Console.WriteLine("索引超出范围");                return false;            }            var current = new RefNode<T>();            Get(index - 1, out current);            var temp = current.Next;            current.Next = node;            node.Next = new RefNode<T>();            node.Next = temp;            Length++;            return true;        }        public bool Delete(int index) //删除指定位置的节点        {                      var p = new RefNode<T>();            if (Get(index - 1, out p))            {                var tp = new RefNode<T>();                Get(index, out tp);                if (tp.Next == null)                    p.Next = null;                else                    p.Next = tp.Next;                Length--;                return true;            }            else                return false;        }        public void Show()//显示链表        {            var p = HeadNode.Next;            Console.WriteLine("There are {0} elements in this  linklist.");            if(p == null)            {                Console.WriteLine("This Link list is a void list;");            }            while(p != null)            {                Console.WriteLine(p.data);                p = p.Next;            }        }    }

下面我们使用指针来实现。使用指针主要注意两点,一是使用指针的地方要用unsafe进行标识;二是指针不能指向不能确定内存大小的泛型类型。为了使指针实现的链表具有通用性,需要使用using来创建别名。即:

using ElemType = System.Int32;  //这里可以根据需要进行更改struct PtrNode  //通过指针实现的链表    {        ElemType data;        unsafe PtrNode* Next;           }

其余操作与引用是相似的,这里就不多说了。
最后,来讲讲静态链表。静态链表是没有指针的高级语言,为了获得链表的便利而想出的实现方法。这种方法有两个数据域,一个用于存储数据,一个用于描述下个节点的位置。描述节点位置的数据称为游标,这种方法又称为游标实现法。这里有两个特殊节点,第一个节点和最后一个节点(注意:不是链表的尾节点),这两个节点不存储数据。第一个节点的游标描述备用空间的第一个节点的位置,最后一个节点的游标存储链表第一个节点的位置。链表的尾节点的游标为0。具体实现如下:

class StaticNode<T> //静态链表节点    {        public T data;        public int cur;        public bool IsEnd;        public StaticNode()        {            data = default(T);            cur = 0;            IsEnd = false;        }    } class StaticLinkList<T>    {        const int MaxSize = 1000;        private int length;        public StaticNode<T>[] Data;        public StaticLinkList()        {            Data = new StaticNode<T>[MaxSize];            for (int i = 0; i < MaxSize; i++)                Data[i] = new StaticNode<T>();            for (int i = 0; i < MaxSize - 1; i++)                Data[i].cur = i + 1;            Data[MaxSize -1 ].cur = 0;                  //目前静态链表为空            length = 0;        }        public int GetLocation(int index)  //得到第index个元素的位置        {            if (index > length || index <= 0)//序号超出范围或序号为零            {                Console.WriteLine("序号为零或序号大于链表长度!");                return 0;            }            int i = Data[MaxSize - 1].cur;            int count = 1;            while(count < index)            {                count++;                i = Data[i].cur;            }            return i;        }        public bool Add(T Elem)   //向表尾添加数据        {            if (Data[0].cur == MaxSize - 1)  //若链表已满                return false;            if (Data[MaxSize - 1].cur == 0)  //若插入的是第一个节点,则更新第一个节点的值                Data[MaxSize - 1].cur = 1;            int i = Data[0].cur;            int prior = 0;                      Data[i].data = Elem;                   Data[0].cur = Data[i].cur;            if (length >= 1)            {                prior = GetLocation(length);                Data[prior].cur = i;            }            Data[i].cur = 0;            length++;            return true;        }        public bool Insert(T Elem, int index) //在第index个位置上插入        {            if(index <= 0 || index > length)            {                Console.WriteLine("索引超出范围!");                return false;            }            if (length >= MaxSize - 2)            {                Console.WriteLine("链表已满!");                return false;            }            int tp = GetLocation(index);            int j = Data[0].cur;            Data[0].cur = Data[j].cur;            Data[j].data = Elem;            Data[j].cur = tp;            if(index != 1)                   //若插入位置不是第一个节点            {                int prior = GetLocation(index - 1);                Data[prior].cur = j;            }            else            {                Data[MaxSize - 1].cur = j;           //插入位置是第一个节点            }            length++;            return true;        }        public bool Delete(int index) //删除第index个元素        {            if(index > length || index <= 0)            {                Console.WriteLine("索引超出范围!");                return false;            }            if(index == 1)   //若删除的是第一个节点            {                int j = Data[MaxSize - 1].cur;                Data[MaxSize - 1].cur = Data[j].cur;                Data[j].cur = Data[0].cur;                Data[0].cur = j;                length--;                return true;            }            else if(index == length) //若删除的是尾节点            {                int prior = GetLocation(index - 1);                int tp = Data[prior].cur;                Data[tp].cur = Data[0].cur;                Data[0].cur = tp;                Data[prior].cur = 0;                length--;                return true;            }            else            {                int prior = GetLocation(index - 1);                int next = GetLocation(index + 1);                int tp = Data[prior].cur;                Data[tp].cur = Data[0].cur;                Data[0].cur = tp;                Data[prior].cur = next;                length--;                return true;            }        }        public int Length()        {            return length;        }        public void Show()        {            Console.WriteLine("This list have {0} elements.", Length());            int tp = Data[MaxSize - 1].cur;            while(tp != 0)            {                Console.WriteLine(Data[tp].data);                tp = Data[tp].cur;            }        }    }
0 0
原创粉丝点击