使用SingleLinkedList扩展类,允许Add,Remove,Contains

创建两个类

SingleLinkedList<T>

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; namespace DevGuideToCollections { /// <summary> /// Represents a strongly typed single linked list. /// </summary> /// <typeparam name="T">Specifies the type of elements in the list.</typeparam> [DebuggerDisplay("Count={Count}")] [DebuggerTypeProxy(typeof(ArrayDebugView))] public class SingleLinkedList<T> { int m_count; SingleLinkedListNode<T> m_head; SingleLinkedListNode<T> m_tail; int m_updateCode; /// <summary> /// Initializes a new instance of the SingleLinkedList(T) class that is empty. /// </summary> public SingleLinkedList() { } /// <summary> /// Initializes a new instance of the SingleLinkedList(T) class that contains the items in the list. /// </summary> /// <param name="items">Adds the items to the end of the SingleLinkedList(T).</param> public SingleLinkedList(IEnumerable<T> items) { foreach (T item in items) { AddToEnd(item); } } /// <summary> /// States if the SingleLinkedList(T) is empty. /// </summary> public bool IsEmpty { get { return m_count <= 0; } } /// <summary> /// Gets the number of nodes actually contained in the SingleLinkedList(T). /// </summary> public int Count { get { return m_count; } } /// <summary> /// Gets the head node in the SingleLinkedList(T). /// </summary> public SingleLinkedListNode<T> Head { get { return m_head; } private set { m_head = value; } } /// <summary> /// Gets the tail node in the SingleLinkedList(T). /// </summary> public SingleLinkedListNode<T> Tail { get { return m_tail; } private set { m_tail = value; } } /// <summary> /// Checks if the specified data is present in the SingleLinkedList(T). /// </summary> /// <param name="data">The data to look for.</param> /// <returns>True if the data is found, false otherwise.</returns> public bool Contains(T data) { return Find(data) != null; } /// <summary> /// Removes all items from the SingleLinkedList(T). /// </summary> public void Clear() { SingleLinkedListNode<T> tmp; // Clean up the items in the list for (SingleLinkedListNode<T> node = m_head; node != null; ) { tmp = node.Next; // Change the count and head pointer in case we throw an exception. // this way the node is removed before we clear the data m_head = tmp; --m_count; // Erase the contents of the node node.Next = null; node.Owner = null; // Move to the next node node = tmp; } if (m_count <= 0) { m_head = null; m_tail = null; } ++m_updateCode; } /// <summary> /// Locates the first node that contains the specified data. /// </summary> /// <param name="data">The data to find.</param> /// <returns>The node that contains the specified data, null otherwise.</returns> public SingleLinkedListNode<T> Find(T data) { if (IsEmpty) { return null; } EqualityComparer<T> comparer = EqualityComparer<T>.Default; // Traverse the list from the Head to Tail. for (SingleLinkedListNode<T> curr = Head; curr != null; curr = curr.Next) { // Return the node we are currently on if it contains the data we are looking for. if (comparer.Equals(curr.Data, data)) { return curr; } } return null; } /// <summary> /// Adds the specified value to the SingleLinkedListNode(T) after the specified node. /// </summary> /// <param name="node">The node to add the value after.</param> /// <param name="value">The value to add.</param> /// <returns>The newly created node that holds the value.</returns> public SingleLinkedListNode<T> AddAfter(SingleLinkedListNode<T> node, T value) { SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(this, value); AddAfter(node, newNode); return newNode; } /// <summary> /// Adds the specified newNode to the SingleLinkedListNode(T) after the specified node. /// </summary> /// <param name="node">The node to add the newNode after.</param> /// <param name="newNode">The node to add.</param> public void AddAfter(SingleLinkedListNode<T> node, SingleLinkedListNode<T> newNode) { if (node == null) { throw new ArgumentNullException("node"); } if (newNode == null) { throw new ArgumentNullException("newNode"); } if (node.Owner != this) { throw new InvalidOperationException("node is not owned by this list"); } if (newNode.Owner != this) { throw new InvalidOperationException("newNode is not owned by this list"); } // The newly added node becomes the tail if you are adding after the tail if (m_tail == node) { m_tail = newNode; } newNode.Next = node.Next; node.Next = newNode; ++m_count; ++m_updateCode; } /// <summary> /// Adds the specified value to the SingleLinkedListNode(T) before the specified node. /// </summary> /// <param name="node">The node to add the value before.</param> /// <param name="value">The value to add.</param> /// <returns>The newly created node that holds the value.</returns> public SingleLinkedListNode<T> AddBefore(SingleLinkedListNode<T> node, T value) { SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(this, value); AddBefore(node, newNode); return newNode; } /// <summary> /// Adds the specified newNode to the SingleLinkedListNode(T) before the specified node. /// </summary> /// <param name="node">The node to add the newNode before.</param> /// <param name="newNode">The node to add.</param> public void AddBefore(SingleLinkedListNode<T> node, SingleLinkedListNode<T> newNode) { if (node == null) { throw new ArgumentNullException("node"); } if (newNode == null) { throw new ArgumentNullException("newNode"); } if (node.Owner != this) { throw new InvalidOperationException("node is not owned by this list"); } if (newNode.Owner != this) { throw new InvalidOperationException("newNode is not owned by this list"); } if (m_head == node) { newNode.Next = m_head; m_head = newNode; } else { // We have to find the node before the one we are inserting in front of SingleLinkedListNode<T> beforeNode = m_head; while (beforeNode != null && beforeNode.Next != node) { beforeNode = beforeNode.Next; } // We should always find node in the list if (beforeNode == null) { throw new InvalidOperationException("Something went wrong"); } newNode.Next = node; beforeNode.Next = newNode; } ++m_count; ++m_updateCode; } /// <summary> /// Adds the value to the beginning of the SingleLinkedList(T). /// </summary> /// <param name="value">The value to add to the beginning of the SingleLinkedList(T).</param> /// <returns>The newly created node that is holding the value.</returns> public SingleLinkedListNode<T> AddToBeginning(T value) { SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(this, value); if (IsEmpty) { m_head = newNode; m_tail = newNode; } else { newNode.Next = m_head; m_head = newNode; } ++m_count; ++m_updateCode; return newNode; } /// <summary> /// Adds the value to the end of the SingleLinkedList(T). /// </summary> /// <param name="value">The value to add to the end of the SingleLinkedList(T).</param> /// <returns>The newly created node that is holding the value.</returns> public SingleLinkedListNode<T> AddToEnd(T value) { SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(this, value); if (IsEmpty) { m_head = newNode; m_tail = newNode; } else { m_tail.Next = newNode; m_tail = newNode; } ++m_count; ++m_updateCode; return newNode; } /// <summary> /// Removes the first occurrence of the specified item from the SingleLinkedList(T). /// </summary> /// <param name="item">The item to remove from the SingleLinkedList(T).</param> /// <returns>True if an item was removed, false otherwise.</returns> public bool Remove(T item) { return Remove(item, false); } /// <summary> /// Removes the first or all occurrences of the specified item from the SingleLinkedList(T). /// </summary> /// <param name="item">The item to remove from the SingleLinkedList(T).</param> /// <param name="alloccurrences">True if all nodes should be removed that contain the specified item, False otherwise</param> /// <returns>True if an item was removed, false otherwise.</returns> public bool Remove(T item, bool alloccurrences) { if (IsEmpty) { return false; } SingleLinkedListNode<T> prev = null; SingleLinkedListNode<T> curr = Head; bool removed = false; EqualityComparer<T> comparer = EqualityComparer<T>.Default; // Start traversing the list at the head while (curr != null) { // Check to see if the current node contains the data we are trying to delete if (!comparer.Equals(curr.Data, item)) { // Assign the current node to the previous node and the previous node to the current node prev = curr; curr = curr.Next; continue; } // Create a pointer to the next node in the previous node if (prev != null) { prev.Next = curr.Next; } if (curr == Head) { // If the current node is the head we will have to assign the next node as the head Head = curr.Next; } if (curr == Tail) { // If the current node is the tail we will have to assign the previous node as the tail Tail = prev; } // Save the pointer for clean up later SingleLinkedListNode<T> tmp = curr; // Advance the current to the next node curr = curr.Next; // Since the node will no longer be used clean up the pointers in it tmp.Next = null; tmp.Owner = null; // Decrement the counter since we have removed a node --m_count; removed = true; if (!alloccurrences) { break; } } if (removed) { ++m_updateCode; } return removed; } /// <summary> /// Removes the specified node from the SingleLinkedList(T). /// </summary> /// <param name="node">The node to remove from the SingleLinkedList(T).</param> public void Remove(SingleLinkedListNode<T> node) { if (IsEmpty) { return; } if (node == null) { throw new ArgumentNullException("node"); } if (node.Owner != this) { throw new InvalidOperationException("The node doesn't belong to this list."); } SingleLinkedListNode<T> prev = null; SingleLinkedListNode<T> curr = Head; // Find the node located before the specified node by traversing the list. while (curr != null && curr != node) { prev = curr; curr = curr.Next; } // The node has been found if the current node equals the node we are looking for if (curr == node) { // Assign the head to the next node if the specified node is the head if (m_head == node) { m_head = node.Next; } // Assign the tail to the previous node if the specified node is the tail if (m_tail == node) { m_tail = prev; } // Set the previous node next reference to the removed nodes next reference. if (prev != null) { prev.Next = curr.Next; } // Null out the removed nodes next pointer to be safe. node.Next = null; node.Owner = null; --m_count; ++m_updateCode; } } /// <summary> /// Copies the elements of the SingleLinkedList(T) to a new array. /// </summary> /// <returns>An array containing copies of the elements of the SingleLinkedList(T).</returns> public T[] ToArray() { T[] retval = new T[m_count]; int index = 0; for (SingleLinkedListNode<T> i = Head; i != null; i = i.Next) { retval[index] = i.Data; ++index; } return retval; } } }
SingleLinkedListNode<T>

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; namespace DevGuideToCollections { /// <summary> /// Represents a node in a SingleLinkedList(T). /// </summary> /// <typeparam name="T">Specifies the type of data in the node.</typeparam> [DebuggerDisplay("Data={Data}")] public class SingleLinkedListNode<T> { SingleLinkedList<T> m_owner; SingleLinkedListNode<T> m_next; T m_data; /// <summary> /// Initializes a new instance of the SingleLinkedList(T) class with the specified data. /// </summary> /// <param name="data">The data that this node will contain.</param> public SingleLinkedListNode(T data) { m_data = data; } /// <summary> /// Initializes a new instance of the SingleLinkedList(T) class with the specified data and owner. /// </summary> /// <param name="data">The data that this node will contain.</param> internal SingleLinkedListNode(SingleLinkedList<T> owner, T data) { m_data = data; m_owner = owner; } /// <summary> /// Returns the next node. /// </summary> public SingleLinkedListNode<T> Next { get { return m_next; } internal set { m_next = value; } } /// <summary> /// Gets or sets the owner of the node. /// </summary> internal SingleLinkedList<T> Owner { get { return m_owner; } set { m_owner = value; } } /// <summary> /// Gets the data contained in the node. /// </summary> public T Data { get { return m_data; } internal set { m_data = value; } } } }

测试方法


static void TestSingleLinkedList() { SingleLinkedList<int> list = new SingleLinkedList<int>(); //Testing add list.AddToEnd(6); list.AddToEnd(9); SingleLinkedListNode<int> nodeAddAfter = list.AddToEnd(5); System.Diagnostics.Debug.Assert(list.Count == 3); SingleLinkedListNode<int> nodeAddBefore1 = list.AddToBeginning(4); list.AddToBeginning(1); list.AddBefore(nodeAddBefore1, 3); System.Diagnostics.Debug.Assert(list.Count == 6); SingleLinkedListNode<int> nodeAddBefore2 = list.AddToEnd(7); list.AddAfter(nodeAddAfter, 6); list.AddBefore(nodeAddBefore2, 9); list.AddBefore(nodeAddBefore2, 9); System.Diagnostics.Debug.Assert(list.Count == 10); // Check the links SingleLinkedListNode<int> node = list.Head; System.Diagnostics.Debug.Assert(node.Data == 1); node = node.Next; System.Diagnostics.Debug.Assert(node.Data == 3); node = node.Next; System.Diagnostics.Debug.Assert(node.Data == 4); node = node.Next; System.Diagnostics.Debug.Assert(node.Data == 6); node = node.Next; System.Diagnostics.Debug.Assert(node.Data == 9); node = node.Next; System.Diagnostics.Debug.Assert(node.Data == 5); node = node.Next; System.Diagnostics.Debug.Assert(node.Data == 6); node = node.Next; System.Diagnostics.Debug.Assert(node.Data == 9); node = node.Next; System.Diagnostics.Debug.Assert(node.Data == 9); node = node.Next; System.Diagnostics.Debug.Assert(node.Data == 7); // Deleting the first 6 from the list list.Remove(6, false); System.Diagnostics.Debug.Assert(list.Contains(6)); //System.Diagnostics.Debug.Assert(list[5] == 6); System.Diagnostics.Debug.Assert(list.Count == 9); // Deleting all 9s from the list list.Remove(9, true); System.Diagnostics.Debug.Assert(!list.Contains(9)); System.Diagnostics.Debug.Assert(list.Count == 6); // Check the DebugView method ArrayDebugView view = new ArrayDebugView(list); object[] values = view.Items; System.Diagnostics.Debug.Assert(values.Length == list.Count); int i = 0; for (SingleLinkedListNode<int> tmpNode = list.Head; tmpNode != null; tmpNode = tmpNode.Next ) { System.Diagnostics.Debug.Assert((int)values[i++] == tmpNode.Data); } // Testing clear list.Clear(); System.Diagnostics.Debug.Assert(list.Count == 0); list.AddToEnd(99); list.AddToBeginning(66); list.AddToEnd(199); System.Diagnostics.Debug.Assert(list.Head.Data == 66); System.Diagnostics.Debug.Assert(list.Head.Next.Data == 99); System.Diagnostics.Debug.Assert(list.Tail.Data == 199); // Test removing System.Diagnostics.Debug.Assert(list.Remove(66)); System.Diagnostics.Debug.Assert(!list.Remove(68)); }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值