254 lines
6.6 KiB
C#
254 lines
6.6 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
namespace BF
|
|
{
|
|
//双向循环列表
|
|
public class BFLinkedList<T> : IEnumerable<T>
|
|
{
|
|
public T FirstItem { get { return First == null ? default(T) : First.item; } }
|
|
public T LastItem { get { return Last == null ? default(T) : Last.item; } }
|
|
|
|
public BFNode<T> First { get { return head; } }
|
|
|
|
public BFNode<T> Last { get { return head == null ? null : head.prev; } }
|
|
|
|
private BFNode<T> head;
|
|
|
|
private int count;
|
|
|
|
public int Count { get { return count; } }
|
|
|
|
private int version;
|
|
public int Version { get { return version; } }
|
|
|
|
private BFStackPool<T> nodePool;
|
|
|
|
private IEqualityComparer<T> comparer;
|
|
|
|
public BFLinkedList(IEqualityComparer<T> comp = null)
|
|
{
|
|
nodePool = new BFStackPool<T>();
|
|
comparer = comp ?? EqualityComparer<T>.Default;
|
|
}
|
|
|
|
public BFNode<T> AddFirst(T t)
|
|
{
|
|
var newNode = nodePool.SafePop(); //Alloc();
|
|
newNode.item = t;
|
|
if (null == head)
|
|
{
|
|
newNode.prev = newNode.next = newNode;
|
|
head = newNode;
|
|
++count;
|
|
++version;
|
|
}
|
|
else
|
|
{
|
|
InternalInsertNodeBefore(head, newNode);
|
|
head = newNode;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public BFNode<T> AddLast(T t)
|
|
{
|
|
var newNode = nodePool.SafePop();//Alloc();
|
|
newNode.item = t;
|
|
if (count == 0)
|
|
{
|
|
newNode.prev = newNode.next = newNode;
|
|
head = newNode;
|
|
++count;
|
|
++version;
|
|
}
|
|
else
|
|
InternalInsertNodeBefore(head, newNode);
|
|
return newNode;
|
|
}
|
|
|
|
public void AddBefore(BFNode<T> node, T t)
|
|
{
|
|
var newNode = nodePool.SafePop();//Alloc();
|
|
newNode.item = t;
|
|
InternalInsertNodeBefore(node, newNode);
|
|
if (node == head)
|
|
head = newNode;
|
|
}
|
|
|
|
public void AddAfter(BFNode<T> node, T t)
|
|
{
|
|
var newNode = nodePool.SafePop();//Alloc();
|
|
newNode.item = t;
|
|
if (null == node.next)
|
|
{
|
|
node.next = newNode;
|
|
newNode.prev = node;
|
|
}
|
|
else
|
|
{
|
|
InternalInsertNodeBefore(node.next, newNode);
|
|
}
|
|
}
|
|
|
|
public bool Contains(T value)
|
|
{
|
|
return null != Find(value);
|
|
}
|
|
|
|
public BFNode<T> Find(T value)
|
|
{
|
|
var node = head;
|
|
if (null == node)
|
|
return null;
|
|
do
|
|
{
|
|
if (comparer.Equals(node.item, value))
|
|
return node;
|
|
node = node.next;
|
|
}
|
|
while (node != head);
|
|
return null;
|
|
}
|
|
|
|
public BFNode<T> FindLast(T value)
|
|
{
|
|
if (null == head)
|
|
return null;
|
|
var last = head.prev;
|
|
var node = last;
|
|
do
|
|
{
|
|
if (comparer.Equals(node.item, value))
|
|
return node;
|
|
node = node.prev;
|
|
}
|
|
while (last != node);
|
|
return null;
|
|
}
|
|
|
|
public void Remove(T value)
|
|
{
|
|
var node = Find(value);
|
|
if (node == null)
|
|
return;
|
|
InternalRemoveNode(node);
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
var current = head;
|
|
while (current != null)
|
|
{
|
|
var temp = current;
|
|
current = current.next;
|
|
temp.Invalidate();
|
|
nodePool.Push(temp);
|
|
}
|
|
}
|
|
|
|
private void InternalRemoveNode(BFNode<T> node)
|
|
{
|
|
if (node.next == node)
|
|
{
|
|
head = null;
|
|
}
|
|
else
|
|
{
|
|
node.next.prev = node.prev;
|
|
node.prev.next = node.next;
|
|
if (head == node)
|
|
head = node.next;
|
|
}
|
|
node.Invalidate();
|
|
nodePool.Push(node);
|
|
--count;
|
|
++version;
|
|
}
|
|
private void InternalInsertNodeBefore(BFNode<T> node, BFNode<T> newNode)
|
|
{
|
|
newNode.next = node;
|
|
newNode.prev = node.prev;
|
|
node.prev.next = newNode;
|
|
node.prev = newNode;
|
|
++count;
|
|
++version;
|
|
}
|
|
|
|
public IEnumerator GetEnumerator()
|
|
{
|
|
return new Enumerator(this);
|
|
}
|
|
|
|
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
|
{
|
|
return new Enumerator(this);
|
|
}
|
|
|
|
public class Enumerator : IEnumerator<T>
|
|
{
|
|
#region interface
|
|
|
|
public T Current { get { return current; } }
|
|
|
|
object System.Collections.IEnumerator.Current { get { return current; } }
|
|
|
|
public bool MoveNext()
|
|
{
|
|
CheckInvalidOperation();
|
|
if (node == null)
|
|
{
|
|
index = linkedList.Count + 1;
|
|
return false;
|
|
}
|
|
++index;
|
|
current = node.item;
|
|
node = node.next;
|
|
if (node == linkedList.head)
|
|
node = null;
|
|
return true;
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
CheckInvalidOperation();
|
|
current = default(T);
|
|
node = linkedList.head;
|
|
version = linkedList.Version;
|
|
index = 0;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
linkedList = null;
|
|
current = default(T);
|
|
node = null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
private T current;
|
|
private BFNode<T> node;
|
|
private int version;
|
|
private int index;
|
|
|
|
public BFLinkedList<T> linkedList;
|
|
|
|
public Enumerator(BFLinkedList<T> ll)
|
|
{
|
|
linkedList = ll;
|
|
node = ll.head;
|
|
version = ll.Version;
|
|
current = default(T);
|
|
index = 0;
|
|
}
|
|
|
|
private void CheckInvalidOperation()
|
|
{
|
|
if (version != linkedList.Version)
|
|
throw new System.InvalidOperationException("foreach 不能修改结构");
|
|
}
|
|
}
|
|
}
|
|
} |