/// <summary>
C#雙向鏈表
/// 雙向鏈表節點類
/// </summary>
/// <typeparam name="T">節點中的存放的數據類型</typeparam>
public class Node<T>
{
/// <summary>
/// 當前節點的數據
/// </summary>
T data;
/// <summary>
/// 節點中存放的數據
/// </summary>
public T Data
{
get { return this.data; }
set { this.data = value; }
}
/// <summary>
/// 當前節點的下一個節點
/// </summary>
Node<T> next;
/// <summary>
/// 下一個節點
/// </summary>
public Node<T> Next
{
get { return this.next; }
set { this.next = value; }
}
/// <summary>
/// 當前節點的上一個節點
/// </summary>
Node<T> prev;
/// <summary>
/// 上一個節點
/// </summary>
public Node<T> Prev
{
get { return prev; }
set { prev = value; }
}
/// <summary>
/// 無參構造:數據爲默認值,下一個節點爲null,上一個節點也爲null
/// </summary>
public Node()
{
this.data = default(T);
this.next = null;
this.prev = null;
}
/// <summary>
/// 構造方法:數據爲傳過來的t,下一個節點爲null,上一個節點也爲null
/// </summary>
/// <param name="t">傳入的元素值</param>
public Node(T t)
{
this.data = t;
this.next = null;
this.prev = null;
}
/// <summary>
/// 構造方法:數據爲t,下一個節點爲node
/// </summary>
/// <param name="t">傳入的元素值</param>
/// <param name="next">上一個節點</param>
/// <param name="prev">下一個節點</param>
public Node(T t, Node<T> next,Node<T> prev)
{
this.data = t;
this.next = next;
this.prev = prev;
}
/// <summary>
/// 此方法在調試過程中使用,可以刪掉
/// </summary>
/// <returns></returns>
public override string ToString()
{
T p = this.prev == null ? default(T) : this.prev.data;
T n = this.next == null ? default(T) : this.next.data;
string s = string.Format("Data:{0},Prev:{1},Next:{2}",data,p,n);
return s;
}
}
/// <summary>
/// 雙向鏈表接口
/// </summary>
/// <typeparam name="T">鏈表中元素的類型</typeparam>
public interface ILinkList<T>
{
void AddFirst(T t);
void AddLast(T t);
void Clear();
int Count { get; }
Node<T> Head { get; set; }
Node<T> Tail { get;set;}
void Insert(int index, T t);
bool IsEmpty { get; }
void RemoveAt(int index);
void RemoveFirst();
void RemoveLast();
Node<T> this[int index] { get; }
}
/// <summary>
/// 雙向鏈表操作類
/// </summary>
/// <typeparam name="T">鏈表中元素的類型</typeparam>
public class LinkList<T> : ILinkList<T>
{
/// <summary>
/// 鏈表頭節點
/// </summary>
Node<T> head;
/// <summary>
/// 鏈表頭節點
/// </summary>
public Node<T> Head
{
get { return head; }
set { head = value; }
}
/// <summary>
/// 鏈表尾節點
/// </summary>
Node<T> tail;
/// <summary>
/// 鏈表尾節點
/// </summary>
public Node<T> Tail
{
get { return tail; }
set { tail = value; }
}
/// <summary>
/// 鏈表大小
/// </summary>
int size = 0;
/// <summary>
/// 添加節點到鏈表的開頭
/// </summary>
/// <param name="t">要添加的數據</param>
public void AddFirst(T t)
{
Node<T> node = new Node<T>(t);
//如果頭爲null
if (head == null)
{
//把頭節點設置爲node
head = node;
//因爲是空鏈表,所以頭尾一致
tail = node;
//大小加一
size++;
return;
}
//原來頭節點的上一個爲新節點
head.Prev = node;
//新節點的下一個爲原來的頭節點
node.Next = head;
//新頭節點爲新節點
head = node;
//大小加一
size++;
}
/// <summary>
/// 添加節點到鏈表的末尾
/// </summary>
/// <param name="t">要添加的數據</param>
public void AddLast(T t)
{
Node<T> node = new Node<T>(t);
//如果頭爲null
if (head == null)
{
//把頭節點設置爲node
head = node;
//因爲是空鏈表,所以頭尾一致
tail = node;
//大小加一
size++;
return;
}
//將原尾節點的下一個設置爲新節點
tail.Next = node;
//將新節點的上一個設置爲原尾節點
node.Prev = tail;
//將尾節點重新設置爲新節點
tail = node;
//大小加一
size++;
}
/// <summary>
/// 在給定的索引處插入數據
/// </summary>
/// <param name="index">索引</param>
/// <param name="t">要插入的數據</param>
public void Insert(int index, T t)
{
Node<T> node = new Node<T>(t);
//索引過小
if (index < 0)
{
throw new IndexOutOfRangeException();
}
//索引過大
if (index >= Count)
{
throw new IndexOutOfRangeException();
}
//如果鏈表是空的,而且索引大於0
if (IsEmpty && index > 0)
{
throw new IndexOutOfRangeException();
}
//如果索引爲0,意味着向鏈表頭部添加節點。
if (index == 0)
{
AddFirst(t);
return;
}
//要插入位置的節點
Node<T> current = head;
int i = 0;
while (true)
{
if (i == index)
{
break;
}
i++;
current = current.Next;
}
//此處非常重要,特別要注意先後次序
//當前節點的上一個的下一個設置爲新節點
current.Prev.Next = node;
//新節點的上一個設置爲當前節點的上一個
node.Prev = current.Prev;
//新節點的下一個設置爲當前節點
node.Next = current;
//當前節點的上一個設置爲新節點
current.Prev = node;
//大小加一
size++;
}
/// <summary>
/// 移除鏈表中的節點
/// </summary>
/// <param name="index">要移除的節點的索引</param>
public void RemoveAt(int index)
{
//鏈表頭節點是空的
if (IsEmpty)
{
throw new Exception("鏈表是空的。");
}
//索引過小
if (index < 0)
{
throw new IndexOutOfRangeException();
}
//索引過大
if (index >= Count)
{
throw new IndexOutOfRangeException();
}
//如果要移除的是頭節點
if (index == 0)
{
RemoveFirst();
return;
}
if (index==size-1)
{
RemoveLast();
return;
}
//要移除的節點
Node<T> current = head;
int i = 0;
while (true)
{
if (i == index)
{
break;
}
i++;
current = current.Next;
}
//當前節點的上一個的Next設置爲當前節點的Next
current.Prev.Next = current.Next;
//當前節點的下一個的Prev設置爲當前節點的Prev
current.Next.Prev = current.Prev;
//大小減一
size--;
}
/// <summary>
/// 移除頭節點
/// </summary>
public void RemoveFirst()
{
//鏈表頭節點是空的
if (IsEmpty)
{
throw new Exception("鏈表是空的。");
}
//如果size爲1,那就是清空鏈表。
if (size==1)
{
Clear();
return;
}
//將頭節點設爲原頭結點的下一個節點,就是下一個節點上移
head = head.Next;
//處理上一步遺留問題,原來的第二個節點的上一個是頭結點,現在第二個要變成頭節點,那要把它的Prev設爲null才能成爲頭節點
head.Prev = null;
//大小減一
size--;
}
/// <summary>
/// 移除尾節點
/// </summary>
public void RemoveLast()
{
//鏈表頭節點是空的
if (IsEmpty)
{
throw new Exception("鏈表是空的。");
}
//如果size爲1,那就是清空鏈表。
if (size == 1)
{
Clear();
return;
}
//尾節點設置爲倒數第二個節點
tail = tail.Prev;
//將新尾節點的Next設爲null,表示它是新的尾節點
tail.Next = null;
//大小減一
size--;
}
/// <summary>
/// 判斷鏈表是否是空的
/// </summary>
public bool IsEmpty
{
get
{
return head == null;
}
}
/// <summary>
/// 鏈表中元素的個數
/// </summary>
public int Count
{
get
{
////也可以採用遍歷的方法獲得長度,遍歷可以從前向後,也可以從後向前
//int count = 0;
////取得鏈表頭部節點
//Node<T> current = new Node<T>();
//current = head;
////遍歷整個鏈表,直到最後一個Next爲null的節點爲止
//while (current!=null)
//{
// count++;
// current = current.Next;
//}
//return count;
return size;
}
}
/// <summary>
/// 清除鏈表中的數據
/// </summary>
public void Clear()
{
head = null;
tail = null;
size = 0;
}
/// <summary>
/// 根據索引獲取鏈表中的節點
/// </summary>
/// <param name="index">整型索引</param>
/// <returns>節點</returns>
public Node<T> this[int index]
{
get
{
//鏈表頭節點是空的
if (head == null)
{
throw new Exception("鏈表是空的。");
}
//索引過小
if (index < 0)
{
throw new IndexOutOfRangeException();
}
//索引過大
if (index >= Count)
{
throw new IndexOutOfRangeException();
}
//取得頭節點
Node<T> current = new Node<T>();
//如果索引在前一半,那麼從前向後找
if (index<size/2)
{
current = head;
int i = 0;
//遍歷鏈表
while (true)
{
//找到第index個節點
if (i == index)
{
break;
}
current = current.Next;
i++;
}
return current;
}
else//如果索引在後一半,那麼從後向前找
{
current = tail;
int i = size;
//遍歷鏈表
while (true)
{
//找到第index個節點
if (i == index)
{
break;
}
current = current.Prev;
i--;
}
return current.Next;
}
}
}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.