C# 双向链表及自定义链表

一、双向链表LinkedList<T> 

      LinkedList<T>集合类没有非泛型集合的类似版本。LinkedList<T>是一个双向链表,其元素指向它前面和后面的元素。 
链表的优点是,如果将元素插入列表的中间位置,使用链表会非常快。在插入一个元素时,只需修改上一个元素的Next引用和下一个元素的Previous引用,使它们引用所插入的元素。在List<T>ArrayList类中,插入一个元素,需要移动该元素后面的所有元素。 
当然,链表也有缺点。链表的元素只能一个接一个地访问,这需要较长的时间来查找位于链表中间或尾部的元素。
链表不仅能在列表中存储元素,还可以给每个元素存储下一个元素和上一个元素的信息。这就是 
LinkedList<T>包含LinkedListNode<T>类型的元素的原因。使用LinkedListNode <T>类,可以获得列表中的下一个元素和上一个元素
#region 链表测试

/**/

/// <summary>

/// 链表测试

/// </summary>

public class TestLinkedList

{

    public void TestLinkList()

    {

        LinkedList<Book> bookList = new LinkedList<Book>();

        Book book1 = new Book { Title = "C#高级编程", Book_Author = new Author { Name = "黄老邪", Address = "桃花岛" }, Price = 128f };

        Book book2 = new Book { Title = "Think in Java", Book_Author = new Author { Name = "欧阳峰", Address = "白驼山" }, Price = 138f };

        Book book3 = new Book { Title = "silverlight", Book_Author = new Author { Name = "一灯大师", Address = "大理" }, Price = 123f };

        Book book4 = new Book { Title = "JavaFx", Book_Author = new Author { Name = "洪七公", Address = "临安" }, Price = 125f };

        Book book5 = new Book { Title = "WPF", Book_Author = new Author { Name = "王重阳", Address = "临安" }, Price = 158f };

 

        /**/

        ///book1添加到链表第一个元素

        bookList.AddFirst(book1);

        /**/

        ///book2添加到链表第一个元素,这时原来的第一个元素会自动退后一位

        bookList.AddFirst(book2);

 

        /**/

        ///实例化一个LinkedListNode 对象

        LinkedListNode<Book> node = new LinkedListNode<Book>(book3);

 

        /**/

        ///LinkedListNode 对象添加到链表最后

        bookList.AddLast(node);

 

        /**/

        ///在最后一个元素后追加一个元素

        bookList.AddAfter(node, book4);

 

        /**/

        ///LinkedListNode 对象前插入一个元素

        bookList.AddBefore(node, book5);

 

        foreach (var item in bookList)

        {

            Console.WriteLine(item.Title);

        }

 

 

        /**/

        ///顺序显示

        ///

        Console.WriteLine("/n/n顺序显示链表内的元素");

        LinkedListNode<Book> firstNode = bookList.First;

        while (firstNode != null)

        {

            Console.WriteLine(firstNode.Value.Title);

            firstNode = firstNode.Next;

 

        }

 

        /**/

        ///逆序显示

        Console.WriteLine("/n/n逆序显示链表内的元素");

        LinkedListNode<Book> lastNode = bookList.Last;

        while (lastNode != null)

        {

            Console.WriteLine(lastNode.Value.Title);

            lastNode = lastNode.Previous;

        }

 

        Console.WriteLine("/n/n排序后的结果");

        var orderList = bookList.OrderBy(book => book.Price);

 

        foreach (var item in orderList)

        {

            Console.WriteLine(string.Format("图书名称{0},价格{1}", item.Title, item.Price));

        }

    }

 

}

 

#endregion

 

二、自定义链表

public class Node<T>

{

        public T data;

        public Node()

        { }

 

        public Node(T data)

        {

            this.data = data;

        }

        public Node<T> next = null;

}

 

    public class Link<T>

    {

        //定义链表的头节点

        private Node<T> head;

 

        //链表初始化

        public Link()

        {

            head = null;

        }

 

        /// <summary>

        /// 链表的长度,遍历整个链表,直到链表结尾

         /// </summary>

        /// <returns>链表的长度</returns>

        public int Count()

        {

            //定义一个节点

            Node<T> p = head;

          int count = 0;//链表计数器

            //遍历链表

            while (p != null)

          {

               count++;

               p = p.next;//移到下一个节点

            }

          return count;

        }

 

 

        /// <summary>

        /// 取链表的第i个节点的值

         /// </summary>

        /// <param name="i">i个节点</param>

        /// <returns>i个节点的值</returns>

        public T GetElem(int i)

        {

            //定义一个节点

            Node<T> p = head;

          int k = 0;//计数器

 

            //如果i大于链表的长度或i小于0,则报出异常

            if (i >= Count() || i < 0)

            {

                throw new Exception("Error");

            }

 

            //如果i大于0且小于链表长度,则遍历链表直到第i个节点为止

            while (k < i)

            {

                k++;

                p = p.next;

            }

            return p.data;

        }

 

        /// <summary>

        /// 在链表的第i个位置上插入新的节点

         /// </summary>

        /// <param name="e">要插入节点的值</param>

        /// <param name="i">链表的第i个节点</param>

        public void Insert(T e, int i)

        {

 

            Node<T> p = new Node<T>(e);//要插入的节点

              Node<T> q = head;

            int k = 0;//计数器

 

            //如果i大于链表的长度或i小于0,则报出异常

            if (i >= Count() || i < 0)

            {

                System.Console.WriteLine("Error");

                return;

            }

 

            //如果在链表头插入,移动头指针

              if (i == 0)

            {

                p.next = head;

                head = p;

                return;

            }

 

            //遍历链表直到第i-1个节点为止

              while (k < i - 1)

            {

                k++;

                q = q.next;

            }

            //把新节点插入在第i个节点的位置

              p.next = q.next;

            q.next = p;

        }

 

        /// <summary>

        /// 删除第i个节点

         /// </summary>

        /// <param name="i">链表的第i个节点</param>

        public void RemoveAt(int i)

        {

            Node<T> p = head;

            int k = 0;//计数器

            //如果i大于链表的长度或i小于0,则报出异常

            if (i < 0 || i >= Count())

            {

                System.Console.WriteLine("Error");

                return;

            }

 

            //如果删除链表头,移动头指针

            if (i == 0)

            {

                head.next = head.next.next;

                return;

            }

 

            //遍历链表直到第i-1个节点为止

            while (k < i - 1)

            {

                k++;

                p = p.next;

            }

 

            //删除第i个节点

            p.next = p.next.next;

        }

 

 

 

 

 

        /// <summary>

        /// 在链表尾加入一个新的节点

        /// </summary>

        /// <param name="e">新的节点的值</param>

        public void Add(T e)

        {

            Node<T> p = new Node<T>(e);//创建一个新的节点

            Node<T> q = new Node<T>();

 

            //如果链表为空,则将新节点赋给头指针

            if (head == null)

            {

                head = p;

                return;

            }

 

            /*--------------------------------------

 

             * 如果链表不为空,则在链表尾加入新的节点

             ----------------------------------------*/

            //从头指针开始遍历,直至链表尾

 

            q = head;

            while (q.next != null)

            {

                q = q.next;

            }

 

            //在链表尾插入新节点

            q.next = p;

 

        }

 

 

 

 

 

 

 

        /// <summary>

        /// 查找某个元素在链表中第一次出现的位置

        /// </summary>

        /// <param name="e">要查找的元素</param>

        /// <returns>这个元素在链表中第一次出现的位置的索引</returns>

 

        public int IndexOf(T e)

        {

            Node<T> p = head;

            int k = 0;//计数器

 

            /*------------------------------------

             * 遍历整个链表,直到找到第一个节点的值

             * 与该元素相等退出,并返回相应的位置索

             * 引。如果没有找到,则返回-1

             -------------------------------------*/

 

            //从头指针开始遍历,找到退出,并返回相应的位置索引

            while (p.next != null)

            {

                if (p.data.Equals(e))

                {

                    return k;

                }

                k++;

                p = p.next;

            }

 

            if (!p.data.Equals(e))

            {

                k++;

            }

 

            //如果没有找到,则返回-1

            return k >= Count() ? -1 : k;

        }

 

 

        /// <summary>

        /// 查找某个元素在链表中最后一次出现的位置

        /// </summary>

        /// <param name="e">要查找的元素</param>

        /// <returns>这个元素在链表中最后一次出现的位置的索引</returns>

 

        public int LastIndexOf(T e)

        {

            Node<T> p = head;

            int index = -1;//最后一次出现的位置索引

            int k = 0;//计数器

 

            /*------------------------------------------------

             * 遍历整个链表,直到链表结束,每发现相应节点的值

             * 与该元素相等,则将该节点的位置索引赋给index

             * 这样index的值就是最后一次的值。如果没有,则返

             * -1

             -------------------------------------------------*/

 

            while (p.next != null)

            {

                if (p.data.Equals(e))

                {

                    index = k;

                }

                k++;

                p = p.next;

            }

 

            if (p.data.Equals(e))

            {

                index = k;

            }

 

            return index;

        }

 

        /// <summary>

        /// 判断链表是否为空

        /// </summary>

        /// <returns></returns>

        public bool Empty()

        {

            return head == null ? true : false;

        }

 

        /// <summary>

        /// 清空链表

        /// </summary>

 

        public void Clear()

        {

            head = null;

        }

 

        /// <summary>

        /// 将链表转成数组

        /// </summary>

        /// <returns>转换后的数组</returns>

 

        public T[] ToArray()

        {

            T[] array = new T[Count()];//定义一个与链表长度相同的数组

            /*------------------------------------------------

             * 遍历链表,将链表的每个节点的值放到相应的数组里

             ------------------------------------------------*/

            Node<T> p = head;

            int i = 0;//数组下标计数器

            while (p.next != null)

            {

                array[i++] = p.data;

                p = p.next;

            }

            array[Count() - 1] = p.data;

            return array;

        }

 

        /// <summary>

        /// 将一个数组加到链表中

         /// </summary>

        /// <param name="a">要加入链表的数组</param>

        public void AddRange(T[] a)

        {

            //遍历整个数组,将数组中的每个元素作为一个新的节点加入到链表中

            for (int i = 0; i < a.Length; i++)

            {

                Add(a[i]);

            }

        }      

 

        /// <summary>

        /// 删除链表中值为某个元素的所有节点

         /// </summary>

        /// <param name="e">要删除节点的值</param>

        public void Remove(T e)

 

        {

            //如果头指针的值等于这个元素,则删这个结点,并将头指针后移

            while (head.data.Equals(e))

            {

                head = head.next;

            }

 

            //如果不是头指针,则删除该节点

            Node<T> p = head;

            while (p.next.next != null)

            {

                if (p.next.data.Equals(e))

                {

                    p.next = p.next.next;

                    continue;

                }

                p = p.next;

            }

            if (p.next.data.Equals(e))

            {

                p.next = null;

            }

        }

 

        /// <summary>

        /// 将链表中所有为某个值的节点替换为另一个值

         /// </summary>

        /// <param name="first">被替换的值</param>

        /// <param name="second">替换的值</param>

        public void Replace(T first, T second)

        {

            Node<T> p = head;

            while (p.next != null)

            {

                if (p.data.Equals(first))

                {

                    p.data = second;

                }

                p = p.next;

            }

 

            if (p.data.Equals(first))

            {

                p.data = second;

            }

        }        

 

        /// <summary>

        /// 链表反转

         /// </summary>

        public void Reverse()

        {

            Node<T> p = head;

            Node<T> newhead = head;

            Node<T> q = p;

            p = p.next;

            newhead.next = null;

            while (p.next != null)

            {

                q = p;

                p = p.next;

                q.next = newhead;

                newhead = q;

 

            }

 

            q = p;

            q.next = newhead;

            newhead = p;

            head = newhead;

 

        }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值