链表

链表

前言:LinkedList<T>是一个双向链表,其元素指向他前面和后面的元素。如下图所示,这样一来,通过移动到下一个元素可以正向的遍历整个链表。通过移动到前一个元素可以反向遍历整个链表。

链表的优点:如果将元素插入列表的中间位置,使用链表就会非常快。在插入一个元素时,只需要修改上一个元素的Next引用和下一个元素的Previous引用,使他们引用所插入的元素。在List<T>类中,插入一个元素时,需要移动该元素后面的所有的元素。

链表的缺点:链表的元素只能一个接一个的访问。这需要较长的时间来查找位于链表中间或者尾部的元素。

链表不能在列表中仅存储元素。存储元素时,链表还必须促成农户每个元素的下一个元素和上一个元素的信息。这就是LinkedList<T>包含LinkedListNode<T>类型的元素的原因。使用LinkedListNode<T>类 ,可以获得列表中的下一个元素和上一个元素。LinkedListNode<T>定义了属性List、Next、Previous、和Value。List属性返回与节点相关的ListedList<T>对象,Next和Previous属性用于遍历链表。访问当前节点之后和之前的节点。Value返回与节点相关的元素,其类型是T。

LinkedList<T>类定义的成员可以访问链表中的第一个和最后一个元素(First和Last)、在指定的位置上插入元素(AddAfter()、AddBefore()、AddFirst()、AddLast()方法)删除指定位置的元素(Remove()、RemoveFirst()、RemoveLast())、从链表的开头(Find()方法)或者结尾(FindLast()方法)开始搜索元素。

我们实例的应用程序使用了一个链表和一个列表。链表包含文档,这与上一个队列例子相同,但文档有 一个额外的优先级。在链表中,文档按照优先级来排序。如果多个文档的优先级相同,这些元素就按照文档的插入的时间来排序。

在链表中添加新文档时,他们应放在优先级相同的最后一个文档的后面。集合LinkedList<Document>包含LinkedListNode<Document>类型的元素。LinkedListNode<T>类添加了Next和Previous属性。使搜索过程中能从一个节点移动到下一个节点上。要引用这些元素,应把List<T>定义为List<LinkedListNode<Document>>。

在上面的例子中,Document类扩展为包含优先级。优先级用类的构造函数设置:

 

    /// <summary>
    /// 文档类
    /// </summary>
    public class Document
    {

        public string Title { get; set; }               //标题
        public string Content { get; set; }             //内容
        public byte Priority { get; set; }              //优先级

        /// <summary>
        /// 构造函数的初始化赋值
        /// </summary>
        /// <param name="title"></param>
        /// <param name="content"></param>
        /// <param name="priority"></param>
        public Document(string title, string content, byte priority)
        {
            this.Title = title;
            this.Content = content;
            this.Priority = priority;
        }

    }

 解决方案的核心是PriorityDocumentManager类。这个类很容易使用。在这个类的公共接口中,可以把新的Document元素添加到链表中,可以检索第一个文档。为了便于测试,它还提供了一个方法,在元素链接到链表中,该方法可以显示集合中的所有的元素。

PriorityDocumentManage类包含两个集合。LinkedList<Document>类型的集合包含所有的文档。List<LinkedListNode<Document>>类型的集合包含最多10个元素的引用。它们是添加指定优先级的新文档的入口点。这两个集合变量都用PriorityDocumentManager类的构造函数来进行实例化。列表集合也用null初始化。

 

    /// <summary>
    /// 优先级文档管理器
    /// </summary>
    public class PriorityDocumentManager
    {

        private readonly LinkedList<Document> _documentList;                    //双向链接列表集合
        private readonly List<LinkedListNode<Document>> _priorityNodes;         //优先级节点              

        /// <summary>
        /// 构造函数初始化
        /// </summary>
        public PriorityDocumentManager()
        {
            _documentList = new LinkedList<Document>();
            _priorityNodes = new List<LinkedListNode<Document>>(10);
            for (int i = 0; i < 10; i++)
            {
                //添加空的节点
                _priorityNodes.Add(new LinkedListNode<Document>(null));
            }
        }

        /// <summary>
        /// 添加文档
        /// </summary>
        /// <param name="d"></param>
        public void AddDocument(Document d)
        {
            if (d == null)
                throw new ArgumentException("d");
            AddDocumentToPriorityNode(d, d.Priority);
        }

        /// <summary>
        /// 显示增加的节点
        /// </summary>
        public void DisplayAddNodes()
        {
            foreach (var doc in _documentList)
            {
                Console.WriteLine("优先级:{0},title:{1}", doc.Priority, doc.Title);
            }
        }

        /// <summary>
        /// 从链表中返回第一个文档(优先级最高的文档),并从链表中删除它.
        /// </summary>
        /// <returns></returns>
        public Document GetDocument()
        {
            Document doc = _documentList.First.Value;
            return doc;
        }

        /// <summary>
        /// 将文档添加到优先节点
        /// </summary>
        /// <param name="doc">文档对象</param>
        /// <param name="priority">优先级</param>
        private void AddDocumentToPriorityNode(Document doc, int priority)
        {
            if (priority > 9 || priority < 0)
            {
                throw new AggregateException("优先级必须是0到9之间的数字");
            }

            //获取节点中包含的值,如果是空的话
            if (_priorityNodes[priority].Value == null)
            {
                //递减优先级
                --priority;
                //如果优先级大于零的话 递归检查
                if (priority >= 0)
                {
                    //检查下一个较低的优先级
                    AddDocumentToPriorityNode(doc, priority);
                }
                //现在没有优先级或者更低的优先级 将新文档添加到末尾
                else
                {
                    //在结尾处添加新节点
                    _documentList.AddLast(doc);
                    //将最后一个节点赋给优先级节点
                    _priorityNodes[doc.Priority] = _documentList.Last;
                }
            }

            //一个优先级节点存在
            else
            {
                //得到节点:当执行到第三个的值的时候,首先拿到上一个值的节点的值
                LinkedListNode<Document> prioNode = _priorityNodes[priority];
                //如果具有相同的优先级节点
                if (priority == doc.Priority)
                {
                    //在指定的现有节点后添加包含指定值得新节点
                    _documentList.AddAfter(prioNode, doc);
                    //将优先级节点设置为具有相同优先级的最后一个节点
                    _priorityNodes[doc.Priority] = prioNode.Next;
                }
                //只有具有较低优先级的优先级节点存在
                else
                {
                    //获得较低优先级的第一个节点
                    LinkedListNode<Document> firstPrioNode = prioNode;
                    while (firstPrioNode.Previous != null && firstPrioNode.Previous.Value.Priority == prioNode.Value.Priority)
                    {
                        firstPrioNode = prioNode.Previous;
                        prioNode = firstPrioNode;
                    }
                    //在指定的现有的节点前添加新值
                    _documentList.AddBefore(firstPrioNode, doc);
                    //将优先值节点设置为新值
                    _priorityNodes[doc.Priority] = firstPrioNode.Previous;
                }
            }
        }

    }

 


在Main方法中,PriorityDocumentManager类用于说明其功能。在链表中添加8个优先级不同的新文档。在显示整个链表。

 

        static void Main(string[] args)
        {

            var pmd = new PriorityDocumentManager();
            pmd.AddDocument(new Document("one", "Sample", 8));
            pmd.AddDocument(new Document("four", "Sample", 8));
            pmd.AddDocument(new Document("two", "Sample", 3));
            pmd.AddDocument(new Document("three", "Sample", 4));
            pmd.AddDocument(new Document("five", "Sample", 1));
            pmd.AddDocument(new Document("six", "Sample", 9));
            pmd.AddDocument(new Document("seven", "Sample", 1));
            pmd.AddDocument(new Document("eight", "Sample", 1));
            pmd.DisplayAddNodes();
            Console.ReadKey();

        }

 


在处理好的结果中,文档先按优先级排序,在按文档添加文档的时间排序。

  

  

posted @ 2017-11-15 20:56  丢了蜡笔小新会哭〆  阅读(299)  评论(0编辑  收藏  举报