代码改变世界

线性表 - 单链表

2011-08-12 23:57  DylanChan  阅读(333)  评论(0编辑  收藏  举报

线性表顺序存储结构缺点:

插入和删除时需要移动大量元素,耗费时间

线性表链式存储结构:

     ◆  用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的

     ◆  链表结构中,除了要存数据元素信息外,还要存储它的后继元素的存储地址

线性表链式存储结构描述

 

 

 带头结点的单链表

 

空链表

 

 实现代码

01    /// <summary>
02    /// 定义单链表结点类
03    /// </summary>
04    public sealed class SinglyLinkedListNode<t>
05    {
06        private T _Item;
07        private SinglyLinkedListNode<t> _NextNode;
08        public T Item
09        {
10            get { return _Item; }
11            set { _Item = value; }
12        }
13        public SinglyLinkedListNode<t> NextNode
14        {
15            get { return _NextNode; }
16            set { _NextNode = value; }
17        }
18 
19        public SinglyLinkedListNode(T item, SinglyLinkedListNode<t> nextItem)
20        {
21            this._Item = item;
22            this._NextNode = nextItem;
23        }
24 
25        public SinglyLinkedListNode()
26            : this(default(T), null)
27        { }
28 
29        public SinglyLinkedListNode(T item)
30            : this(item, null)
31        { }
32 
33        public SinglyLinkedListNode(SinglyLinkedListNode<t> nextItem)
34            : this(default(T), nextItem)
35 
36        { }
37    }
01    /// <summary>
02    /// 定义单链表类(带头结点)
03    /// </summary>
04    public sealed class SinglyLinkedList<t> : IEnumerable<t>
05    {
06        private SinglyLinkedListNode<t> _HeadElement;
07        public SinglyLinkedListNode<t> HeadElement
08        {
09            get { return _HeadElement; }
10            set { _HeadElement = value; }
11        }
12 
13        //构造函数,构造带头结点的空表
14        public SinglyLinkedList()
15        {
16            this._HeadElement = new SinglyLinkedListNode<t>();
17        }
18 
19        //实现索引
20        public T this[int index]
21        {
22            get { return this.GetElement(index + 1); }
23        }
24 
25        /// <summary>
26        /// 判断链表是否为空
27        /// </summary>
28        /// <returns>true,链表为空</returns>
29        public bool IsEmpty()
30        {
31            return this._HeadElement.NextNode == null;
32        }
33 
34        /// <summary>
35        /// 清空链表
36        /// </summary>
37        public void Clear()
38        {
39            //_HeadElement的后继结点设为null,所有后继结点由于失去引用,等待GC自动回收
40            this._HeadElement.NextNode = null;
41        }
42 
43        /// <summary>
44        /// 返回链表中的元素数量
45        /// </summary>
46        public int Count()
47        {
48            int result = 0;
49            //指向头结点
50            SinglyLinkedListNode<t> listNode = this._HeadElement;
51            while (listNode.NextNode != null)
52            {
53                result++;
54                //移动指针,指向下一结点
55                listNode = listNode.NextNode;
56            }
57            return result;
58        }       
59 
60        /// <summary>
61        /// 遍历单链表
62        /// </summary>
63        public void ShowSinglyLinkedList()
64        {
65            SinglyLinkedListNode<t> listNode = this._HeadElement;
66            while (listNode.NextNode != null)
67            {
68                Console.WriteLine(listNode.NextNode.Item);
69                listNode = listNode.NextNode;
70            }
71        }
72 
73        //实现foreach遍历
74        public IEnumerator<t> GetEnumerator()
75        {
76            SinglyLinkedListNode<t> listNode = this._HeadElement;
77            while (listNode.NextNode != null)
78            {
79                yield return listNode.NextNode.Item;
80                listNode = listNode.NextNode;
81            }
82        }
83 
84        IEnumerator System.Collections.IEnumerable.GetEnumerator()
85        {
86            return GetEnumerator();
87        }
88    }
单链表的创建
01        /// <summary>
02        ///  以“头插法”方式创建单链表,不必每次都循环到尾部,时间复杂度为O(1)
03        /// </summary>
04        /// <param name="item">
05        public void CreateListHead(T item)
06        {
07            //实例化一个待插入的新结点
08            SinglyLinkedListNode<t> firstNode = new SinglyLinkedListNode<t>(item);
09            //空表时,直接插入,头结点的后继结点作为第一结点
10            if (this._HeadElement.NextNode == null)
11            {
12                this._HeadElement.NextNode = firstNode;
13                return;
14            }
15            //原来的第一结点作为新结点的后继结点
16            firstNode.NextNode = this._HeadElement.NextNode;
17            //新结点作为头结点的后继结点
18            this._HeadElement.NextNode = firstNode;
19        }
20 
21        /// <summary>
22        /// 以“尾插法”方式创建单链表,需要循环到尾部,时间复杂度为O(n)
23        /// </summary>
24        /// <param name="item">
25        public void CreateListTail(T item)
26        {
27            SinglyLinkedListNode<t> lastNode = new SinglyLinkedListNode<t>(item);
28            //空表时,直接插入,头结点的后继结点作为第一结点
29            if (this._HeadElement.NextNode == null)
30            {
31                this._HeadElement.NextNode = lastNode;
32            }
33            else
34            {
35                //指向头结点
36                SinglyLinkedListNode<t> listNode = this._HeadElement;
37                //循环至尾部
38                while (listNode.NextNode != null)
39                {
40                    listNode = listNode.NextNode;
41                }
42                //插入结点
43                listNode.NextNode = lastNode;
44            }
45        }

单链表的读取

获取链表第 i 个数据的算法思路

     ◆   判断链表是否为空、插入位置是否正确

     ◆   声明一结点listNode,并指向头结点( _HeadElement )

     ◆   初始化变量 j,j 从 1 开始

     ◆   当 j <= i 时,遍历链表,让listNode的指针向后移动,不断指向下一结点,直到指向指定位置的结点,j 累加 1

     ◆   返回结点listNode的数据
01        /// <summary>
02        /// 获取指定位置的元素
03        /// </summary>
04        /// <param name="i">指定的位置,从1开始
05        /// <returns>返回单链表的元素</returns>
06        public T GetElement(int i)
07        {
08            if (IsEmpty())
09            {
10                Console.WriteLine("There Are Elements In This Linear List!");
11                return default(T);
12            }
13            if (i < 0 || i > this.Count())
14            {
15                Console.WriteLine("This Location Is Not Exits!");
16                return default(T);
17            }
18 
19            //指向头结点
20            SinglyLinkedListNode<t> listNode = this._HeadElement;
21            int j = 1;
22            //通过循环,直到指向指定位置的节点
23            while (j <= i)
24            {
25                //移动指针,指向下一结点
26                listNode = listNode.NextNode;
27                j++;
28            }
29            return listNode.Item;
30        }
获取链表某个数据所在链表的位置的算法思路

     ◆   判断链表是否为空

     ◆   声明一结点listNode,并指向头结点( _HeadElement )

     ◆   初始化变量 result 为 0

     ◆   当结点的后继结点不为Null时,遍历链表

     ◆   result 累加 1

     ◆   比较结点listNode的数据与指定的元素是否相同,若相同,返回 result;若不相同,让listNode的指针向后移动,不断指向下一结点

01        /// <summary>
02        /// 获取指定元素的位置
03        /// </summary>
04        /// <param name="item">指定的元素
05        /// <returns>返回单链表的位置</returns>
06        public int LocateElement(T item)
07        {
08            if (IsEmpty())
09            {
10                Console.WriteLine("There Are No Elements In This Linear List!");
11                return 0;
12            }
13            //指向头结点
14            SinglyLinkedListNode<t> listNode = this._HeadElement;
15            int result = 0;
16            //遍历双向链表,指针指向表尾,循环结束
17            while (listNode.NextNode != null)
18            {
19                result++;
20                //比较链表元素与指定元素是否相等
21                if (listNode.NextNode.Item.Equals(item))
22                {
23                    return result;
24                }
25                //移动指针,指向下一结点
26                listNode = listNode.NextNode;
27            }
28            return 0;
29        }

插入操作

     指定节点之后插入新结点

 

01        /// <summary>
02        /// 指定节点之后插入新结点
03        /// </summary>
04        /// <param name="item">指定结点
05        /// <param name="newItem">新结点
06        public void InsertAfterByValue(T item, T newItem)
07        {
08            int location = LocateElement(item);
09            if (location < 1)
10            {
11                Console.WriteLine("Inserted Error!");
12                return;
13            }
14            //定义待插入结点
15            SinglyLinkedListNode<t> insertNode = new SinglyLinkedListNode<t>(newItem);
16            //指向头结点
17            SinglyLinkedListNode<t> listNode = this._HeadElement;
18            int j = 0;
19            while (listNode.NextNode != null)
20            {
21                if (j == location)
22                {
23                    //指定结点的后继结点作为新结点的后继结点
24                    insertNode.NextNode = listNode.NextNode;
25                    //新结点作为指定结点的后继结点
26                    listNode.NextNode = insertNode;
27                    return;
28                }
29                j++;
30                //移动指针,指向下一结点
31                listNode = listNode.NextNode;
32            }
33        }

     指定节点之前插入新结点

 

01        /// <summary>
02        /// 指定节点之前插入新结点
03        /// </summary>
04        /// <param name="item">指定结点
05        /// <param name="newItem">新结点
06        public void InsertBeforeByValue(T item, T newItem)
07        {
08            int location = LocateElement(item);
09            if (location > 0)
10            {
11                InsertByLocation(newItem, location);
12                return;
13            }
14            Console.WriteLine("Inserted Error!");
15        }
16 
17        /// <summary>
18        /// 指定位置插入新节点
19        /// </summary>
20        /// <param name="item">新节点
21        /// <param name="location">指定位置序号,从1开始
22        public void InsertByLocation(T item, int location)
23        {
24            if (location < 1 && location > this.Count())
25            {
26                Console.WriteLine("Inserted Error!");
27                return;
28            }
29            //定义待插入结点
30            SinglyLinkedListNode<t> insertNode = new SinglyLinkedListNode<t>(item);
31            //空表时直接插入
32            if (this._HeadElement.NextNode == null)
33            {
34                this._HeadElement.NextNode = insertNode;
35                return;
36            }
37            //定义头结点
38            SinglyLinkedListNode<t> listNode = this._HeadElement;
39            int j = 0;
40            //在最开头插入
41            if (location == 1)
42            {
43                //头结点的后继结点作为新结点的后继结点
44                insertNode.NextNode = this._HeadElement.NextNode;
45                //新结点作为头结点的后继结点
46                this._HeadElement.NextNode = insertNode;
47            }
48            else
49            {
50                while (listNode.NextNode != null)
51                {
52                    if (j == (location - 1))
53                    {
54                        //原来该位置的结点作为新结点的后继结点
55                        insertNode.NextNode = listNode.NextNode;
56                        //新结点作为该位置的结点
57                        listNode.NextNode = insertNode;
58                        return;
59                    }
60                    j++;
61                    //指向下一结点
62                    listNode = listNode.NextNode;
63                }
64            }
65        }

 删除操作

 

01        /// <summary>
02        /// 删除指定位置的元素
03        /// </summary>
04        /// <param name="i">链表位置,i从1开始
05        public void Delete(int i)
06        {
07            if (this.IsEmpty())
08            {
09                Console.WriteLine("This Linear List Is Empty!");
10                return;
11            }
12            if (i < 1 && i > this.Count())
13            {
14                Console.WriteLine("Deleted Error!");
15                return;
16            }
17            //指向头结点
18            SinglyLinkedListNode<t> listNode = this._HeadElement;
19            //删除的位置为第一个结点
20            if (i == 1)
21            {
22                listNode.NextNode = listNode.NextNode.NextNode;
23            }
24            else
25            {
26                int j = 1;
27                //循环到要删除结点的前一结点
28                while (j <= (i - 1))
29                {
30                    //移动结点
31                    listNode = listNode.NextNode;
32                    j++;
33                }
34                //删除结点的后继结点作为删除结点的前一结点的后继结点
35                listNode.NextNode = listNode.NextNode.NextNode;
36            }
37        }