您的位置:首页 > 理论基础 > 数据结构算法

数据结构(2):链表

2016-03-13 23:15 501 查看
在上一篇文章中,实现线性表中的顺序表,对于插入、删除操作比较频繁的数据来说,用顺序表就不是很经济了,这时候链表就排上用场

在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;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: