.NET源码中的链表
来源:互联网 发布:java html标签转pdf 编辑:程序博客网 时间:2024/06/05 18:23
.NET中自带的链表是LinkedList类,并且已经直接实现成了双向循环链表。
其节点类LinkedListNode的数据结构如下,数据项包括指示到某个链表的引用,以及左,右节点和值。
public sealed class LinkedListNode<T> { internal LinkedList<T> list; internal LinkedListNode<T> next; internal LinkedListNode<T> prev; internal T item; }
另外,获取前一个节点和后一个节点的实现如下:注意:里面的if-else结构的意义是当前一个(后一个)节点不为空且不是头节点时才不返回null,这样做的意义是当链表内只有1个节点时,其prev和next是指向自身的。
[__DynamicallyInvokable] public LinkedListNode<T> Next { [__DynamicallyInvokable] get { if (this.next != null && this.next != this.list.head) return this.next; else return (LinkedListNode<T>) null; } } [__DynamicallyInvokable] public LinkedListNode<T> Previous { [__DynamicallyInvokable] get { if (this.prev != null && this != this.list.head) return this.prev; else return (LinkedListNode<T>) null; } }
过有一个把链表置为无效的方法定义如下:
internal void Invalidate() { this.list = (LinkedList<T>) null; this.next = (LinkedListNode<T>) null; this.prev = (LinkedListNode<T>) null; }
而LinkedList的定义如下:主要的两个数据是头节点head以及长度count。
public class LinkedList<T> : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable, ISerializable, IDeserializationCallback { internal LinkedListNode<T> head; internal int count; internal int version; private object _syncRoot; private SerializationInfo siInfo; private const string VersionName = "Version"; private const string CountName = "Count"; private const string ValuesName = "Data";
而对此链表的主要操作,包括:
- 插入节点到最后,Add(),也是AddLast()。
- 在某个节点后插入,AddAfter(Node, T)。
- 在某个节点前插入,AddBefore(Node, T)。
- 插入到头节点之前,AddFirst(T)。
- 清除所有节点,Clear()。
- 是否包含某个值,Contains(T),也就是Find()。
- 查找某个节点的引用,Find()和FindLast()。
- 复制到数组,CopyTo(Array)
- 删除某个节点,Remove(T)。
另外有几个内部方法,用来支撑复用插入和删除操作:
- 内部插入节点,InternalInsertNodeBefore()
- 内部插入节点到空链表,InternalInsertNodeToEmptyList()
- 内部删除节点,InternalRemoveNode()
- 验证新节点是否有效,ValidateNewNode()
- 验证节点是否有效,ValidateNode()
插入新节点到链表最后的代码如下:
public void AddLast(LinkedListNode<T> node) { this.ValidateNewNode(node); if (this.head == null) this.InternalInsertNodeToEmptyList(node); else this.InternalInsertNodeBefore(this.head, node); node.list = this; }插入操作的第一步是验证节点是否有效,即节点不为null,且节点不属于其他链表。
internal void ValidateNewNode(LinkedListNode<T> node) { if (node == null) throw new ArgumentNullException("node"); if (node.list != null) throw new InvalidOperationException(SR.GetString("LinkedListNodeIsAttached")); }
如果头节点为空,则执行插入到空链表的操作:将节点的next和prev都指向为自己,并作为头节点。
private void InternalInsertNodeToEmptyList(LinkedListNode<T> newNode) { newNode.next = newNode; newNode.prev = newNode; this.head = newNode; ++this.version; ++this.count; }如果头节点不为空,则执行插入到头节点之前(注:因为是双向链表,所以插到头节点之前就相当于插到链表的最后了),具体的指针指向操作如下:
private void InternalInsertNodeBefore(LinkedListNode<T> node, LinkedListNode<T> newNode) { newNode.next = node; newNode.prev = node.prev; node.prev.next = newNode; node.prev = newNode; ++this.version; ++this.count; }
而插入新节点到指定节点之后的操作如下:同样还是调用的内部函数,把新节点插入到指定节点的下一个节点的之前。有点绕,但确实让这个内部函数起到多个作用了。
public void AddAfter(LinkedListNode<T> node, LinkedListNode<T> newNode) { this.ValidateNode(node); this.ValidateNewNode(newNode); this.InternalInsertNodeBefore(node.next, newNode); newNode.list = this; }
而插入新节点到指定节点之前的操作如下:直接调用插入新节点的内部函数,另外还要判断指定的节点是否是头节点,如果是的话,要把头节点变成新的节点。
public void AddBefore(LinkedListNode<T> node, LinkedListNode<T> newNode) { this.ValidateNode(node); this.ValidateNewNode(newNode); this.InternalInsertNodeBefore(node, newNode); newNode.list = this; if (node != this.head) return; this.head = newNode; }
把新链表插入到第一个节点(也就是变成头节点)的操作如下:如果链表为空就直接变成头节点,否则就插入到头节点之前,取代头节点。
public void AddFirst(LinkedListNode<T> node) { this.ValidateNewNode(node); if (this.head == null) { this.InternalInsertNodeToEmptyList(node); } else { this.InternalInsertNodeBefore(this.head, node); this.head = node; } node.list = this; }
查找链表中某个值的操作如下:注意直接返回null的条件是头节点为空。然后就是遍历了,因为是双向链表,所以要避免死循环(遍历到头节点时跳出)。
public LinkedListNode<T> Find(T value) { LinkedListNode<T> linkedListNode = this.head; EqualityComparer<T> @default = EqualityComparer<T>.Default; if (linkedListNode != null) { if ((object) value != null) { while (!@default.Equals(linkedListNode.item, value)) { linkedListNode = linkedListNode.next; if (linkedListNode == this.head) goto label_8; } return linkedListNode; } else { while ((object) linkedListNode.item != null) { linkedListNode = linkedListNode.next; if (linkedListNode == this.head) goto label_8; } return linkedListNode; } }label_8: return (LinkedListNode<T>) null; }
删除某个节点的操作如下:
public void Remove(LinkedListNode<T> node) { this.ValidateNode(node); this.InternalRemoveNode(node); }
同样,内部删除节点的实现如下:如果节点指向自己,说明是头节点,所以直接把头节点置null。然后就是指针的指向操作了。
internal void InternalRemoveNode(LinkedListNode<T> node) { if (node.next == node) { this.head = (LinkedListNode<T>) null; } else { node.next.prev = node.prev; node.prev.next = node.next; if (this.head == node) this.head = node.next; } node.Invalidate(); --this.count; ++this.version; }
而清空链表的操作如下:遍历链表,逐个设置为无效,最后将内部的头节点也置为null。
public void Clear() { LinkedListNode<T> linkedListNode1 = this.head; while (linkedListNode1 != null) { LinkedListNode<T> linkedListNode2 = linkedListNode1; linkedListNode1 = linkedListNode1.Next; linkedListNode2.Invalidate(); } this.head = (LinkedListNode<T>) null; this.count = 0; ++this.version; }
链表转数组的实现如下:首先判断入参的有效性,然后从头节点开始遍历,依次复制到数组中,直到头结点(尽头)。
public void CopyTo(T[] array, int index) { if (array == null) throw new ArgumentNullException("array"); if (index < 0 || index > array.Length) { throw new ArgumentOutOfRangeException("index", SR.GetString("IndexOutOfRange", new object[1] { (object) index })); } else { if (array.Length - index < this.Count) throw new ArgumentException(SR.GetString("Arg_InsufficientSpace")); LinkedListNode<T> linkedListNode = this.head; if (linkedListNode == null) return; do { array[index++] = linkedListNode.item; linkedListNode = linkedListNode.next; } while (linkedListNode != this.head); } }
以上。
0 0
- .NET源码中的链表
- .NET源码中的栈
- .NET源码中的队列
- .NET源码中的SortedSet
- .net中的验证码源码
- .net中的验证码源码
- .NET源码中的HashSet<T>
- .NET源码中的Stream类
- .NET源码中的GC类
- .NET源码中的二分查找实现
- .NET源码中的随机数生成类
- asp.net防盗链源码
- ASP.NET 防盗链源码
- ASP.NET 防盗链源码
- ASP.NET 防盗链源码
- .NET源码中的SortedDictionary<TKey, TValue>和SortedList<TKey, TValue>
- .net中的防盗链
- asp.net中的联动菜单 - 清清月儿 .NET万花筒 Asp.net技术 Asp.net教程 Asp.net源码 Asp.net基础 Asp.net控件 Asp.net入门 - CSDNBlog
- 支持并发的http客户端(基于tcp连接池以及netty)
- Ubuntu启动、停止、重启MySQL,查看MySQL错误日志、中文编码错误
- C/C++迭代器使用详解
- FFMPEG视音频编解码零基础学习方法
- Android音频: 如何使用AudioTrack播放一个WAV格式文件?
- .NET源码中的链表
- Spark resource links
- 代码行数统计
- VC读取Word剪贴板中的图片
- hdu1846(博弈)
- CentOS
- LeetCode 83 Remove Duplicates from Sorted List II
- 用jquery制作一个简单的导航栏
- Mysql语句的练习笔记