数据结构(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
- 数据结构-链表(2)
- 数据结构(2):链表
- 【数据结构2】链表
- Redis-数据结构-2-链表
- Java中的数据结构(2)----链表
- 数据结构之(2)链表
- 数据结构学习记录-链表2
- 数据结构---链表
- 数据结构 - 链表
- 【数据结构】链表
- 数据结构-链表
- '数据结构' 链表
- 数据结构-链表
- 【数据结构】链表
- 数据结构--链表
- 【数据结构】 链表
- 数据结构--链表
- 数据结构-链表
- makefile 模板
- Java day02 基本语句练习 进制转换
- RGB各种颜色对照表
- java多线程
- 杭电-1717-杭电-1717-小数化分数2
- 数据结构(2):链表
- 【hibernate】我的第一个小例子
- 【操作系统原理】信号量机制
- HDU 5644 King's Pliot【费用流】
- fio 磁盘读写性能测试
- 推荐开发工具系列之--FireGestures(火狐手势命令)
- java.lang.NullPointerException at org.apache.jsp.index_jsp._jspInit(index_jsp.java:22)
- HTML笔记一
- visual studio生成自己的动态静态链接库