线性表(六):.NET Framework泛型LinkedList类
2012-03-17 19:56:22一、结点为LinkedListNode
该对象的实现如下
//在LinkedList<T>中LinkedListNode<T>相互之间构成双向环状链表
//该双向环状链表通过内部成员next、prev来实现,但对于外部不可见
//对于外部Next、Previous表现为双向链表,首尾不构成环
public sealed class LinkedListNode<T>
{
internal LinkedList<T> list;
internal LinkedListNode<T> next;
internal LinkedListNode<T> prev;
internal T item;
public LinkedListNode(T value)
{
this.item = value;
}
internal LinkedListNode(LinkedList<T> list, T value)
{
this.list = list;
this.item = value;
}
public LinkedList<T> List
{
get { return list; }
}
public LinkedListNode<T> Next
{
get { return next == null || next == list.head ? null : next; }
}
public LinkedListNode<T> Previous
{
get { return prev == null || this == list.head ? null : prev; }
}
public T Value
{
get { return item; }
set { item = value; }
}
internal void Invalidate()
{
list = null;
next = null;
prev = null;
}
}
二、外部表现为双向线性链表,内部实现实际为双向环状链表
通过LinkedListNode
public class LinkedList<T> : ICollection<T>, System.Collections.ICollection, ISerializable, IDeserializationCallback
{
internal LinkedListNode<T> head; //双向环状链表的第一个结点,
internal int count; //结点个数
internal int version;
private SerializationInfo siInfo; //临时变量,用于反序列化
//......其他成员
public LinkedListNode<T> First
{
get { return head; }
}
//注意如何将内部表示的双向循环链表,外部体现的双向线性链表
public LinkedListNode<T> Last
{
get { return head == null ? null : head.prev; }
}
//......其他代码
}
三、插入、删除操作的实现
因为LinkedList
private void InternalInsertNodeBefore(LinkedListNode<T> node, LinkedListNode<T> newNode)
{
newNode.next = node;
newNode.prev = node.prev;
node.prev.next = newNode;
node.prev = newNode;
version++;
count++;
}
//向空链表插入第一个结点
private void InternalInsertNodeToEmptyList(LinkedListNode<T> newNode)
{
Debug.Assert(head == null && count == 0, "LinkedList must be empty when this method is called!");
newNode.next = newNode;
newNode.prev = newNode;
head = newNode;
version++;
count++;
}
internal void InternalRemoveNode(LinkedListNode<T> node)
{
Debug.Assert(node.list == this, "Deleting the node from another list!");
Debug.Assert(head != null, "This method shouldn't be called on empty list!");
if (node.next == node)
{
Debug.Assert(count == 1 && head == node, "this should only be true for a list with only one node");
head = null;
}
else
{
node.next.prev = node.prev;
node.prev.next = node.next;
if (head == node)
{
head = node.next;
}
}
node.Invalidate();
count--;
version++;
}
四、Find和FindLast方法
直接看代码,时间复杂度为O(n)
public LinkedListNode<T> Find(T value)
{
LinkedListNode<T> node = head;
EqualityComparer<T> c = EqualityComparer<T>.Default;
if (node != null)
{
if (value != null)
{
do
{
if (c.Equals(node.item, value))
{
return node;
}
node = node.next;
} while (node != head);
}
else
{
do
{
if (node.item == null)
{
return node;
}
node = node.next;
} while (node != head);
}
}
return null;
}
public LinkedListNode<T> FindLast(T value)
{
if (head == null) return null;
LinkedListNode<T> last = head.prev;
LinkedListNode<T> node = last;
EqualityComparer<T> c = EqualityComparer<T>.Default;
if (node != null)
{
if (value != null)
{
do
{
if (c.Equals(node.item, value))
{
return node;
}
node = node.prev;
} while (node != last);
}
else
{
do
{
if (node.item == null)
{
return node;
}
node = node.prev;
} while (node != last);
}
}
return null;
}
五、序列化与反序列化
如何将链表序列化为数组,.net framework提供了GetObjectData和OnDeserialization
//该序列化是将链表数据结构转换为数组保存
//序列化后的头两个int长度链表的version和结点个数
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null)
{
throw new ArgumentNullException("info");
}
info.AddValue(VersionName, version);
info.AddValue(CountName, count);
if (count != 0)
{
T[] array = new T[Count];
CopyTo(array, 0);
info.AddValue(ValuesName, array, typeof(T[]));
}
}
public virtual void OnDeserialization(Object sender)
{
if (siInfo == null)
{
return;
}
int realVersion = siInfo.GetInt32(VersionName);
int count = siInfo.GetInt32(CountName);
if (count != 0)
{
T[] array = (T[])siInfo.GetValue(ValuesName, typeof(T[]));
if (array == null)
{
throw new SerializationException(SR.GetString(SR.Serialization_MissingValues));
}
for (int i = 0; i < array.Length; i++)
{
AddLast(array[i]);
}
}
else
{
head = null;
}
version = realVersion;
siInfo = null;
}