线性表 - 单链表
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 | } |