写在前面
模块化编程是大多数初学者必经之路,然后可能你走向了结构化编程,链表是一种典型结构模式,它的出现克服了数组必须预先知道大小的缺陷,听不懂?你只需要记住,链表结构非常牛叉就可以了,学习这种结构对我们的逻辑思维有很大提升。
什么是链表结构呢?
链表是一种物理存储单元上非连续、非顺序的存储结构。比如A->B->C,这种结构,我们可以理解为A连接着B,B连接C,像这种结构我们就叫做链表结构。对了,火车的车厢,其实就是链表的结构的最好说明
为什么要有链表结构呢?
学过计算机的都知道数组(Array),数组常用切好用,但也存在问题。首先,数组必须需要知道空间大小(int[] age = new int[100], 必须声明长度),其次,对于元素之间插入、删除操作效率很低(如何在数组中间插入一个元素?)。
链表的出现,完美的解决了这些问题。
如何实现链表
首先我们需要声明一种结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
//链表结构: 构造节点 - 连接节点
//Template
class Node
{
public int num;
//指向下一个元素
public Node next;
}
//链表结构: 构造节点 - 连接节点
//Template
class Node
{
public int num;
//指向下一个元素
public Node next;
}
|
我们可以把上面的这种结构看做是一个礼品盒,可以存放整形数值。
然后我们创建一个MyList先生,这位先生就使用Node去存放整形物品,而且使用了链表结构哦!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
class MyList
{
public Node currentNode;
public Node point;
public MyList()
{
currentNode = new Node();
}
//存放物品
public void Add( int value)
{
//第一次
if (point == null )
{
currentNode.num = value;
point = currentNode;
}
else //2 3 4..... 次
{
Node temp = new Node();
temp.num = value;
point.next = temp;
//更新指针
point = temp;
}
}
}
class MyList
{
public Node currentNode;
public Node point;
public MyList()
{
currentNode = new Node();
}
//存放物品
public void Add( int value)
{
//第一次
if (point == null )
{
currentNode.num = value;
point = currentNode;
}
else //2 3 4..... 次
{
Node temp = new Node();
temp.num = value;
point.next = temp;
//更新指针
point = temp;
}
}
}
|
然后,我们可以在客户端测试一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
public static void Main ( string [] args)
{
MyList< int > mList = new MyList< int >();
//添加元素
mList.Add(1);
mList.Add(11);
mList.Add(111);
mList.Add(1111);
while (mList.currentNode != null )
{
Console.WriteLine (mList.currentNode.num);
mList.currentNode = mList.currentNode.next;
}
}
public static void Main ( string [] args)
{
MyList< int > mList = new MyList< int >();
//添加元素
mList.Add(1);
mList.Add(11);
mList.Add(111);
mList.Add(1111);
while (mList.currentNode != null )
{
Console.WriteLine (mList.currentNode.num);
mList.currentNode = mList.currentNode.next;
}
}
|
我们自己定义的一个整形集合就这样ok了。它有两个优点:可以存放任意多个元素!方便元素的插入和删除。
双向链表的定义和简单操作:
双向链表其实是单链表的改进。当我们对单链表进行操作时,有时你要对某个结点的直接前驱进行操作时,又必须从表头开始查找。这是由单链表结点的结构所限制的。因为单链表每个结点只有一个存储直接后继结点地址的链域,那么能不能定义一个既有存储直接后继结点地址的链域,又有存储直接前驱结点地址的链域的这样一个双链域结点结构呢?这就是双向链表。在双向链表中,结点除含有数据域外,还有两个链域,一个存储直接后继结点地址,一般称之为右链域;一个存储直接前驱结点地址,一般称之为左链域。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
namespace DounlyLinkedlist
{
//定义双向链表的结点
public class Node
{
public Object Element;
public Node FLink;
public Node BLink;
public Node()
{
Element = null ;
FLink = null ;
BLink = null ;
}
public Node(Object element)
{
Element = element;
FLink = null ;
BLink = null ;
}
}
//链表操作的类
public class LinkedList
{
public Node Header;
public LinkedList()
{
Header = new Node( "Header" );
Header.FLink = null ;
Header.BLink = null ;
}
//查找结点
private Node Find(Object item)
{
Node Current = new Node();
Current = Header;
while (Current.Element != item)
{
Current = Current.FLink;
}
return Current;
}
//插入结点
public void InsertNode(Object item,Object postionItem)
{
Node Current = new Node();
Node NewItem = new Node(item);
Current = Find(postionItem);
if (Current != null )
{
NewItem.FLink = Current.FLink;
NewItem.BLink = Current;
Current.FLink = NewItem;
}
}
//删除结点
public void Remove(Object item)
{
Node P = Find(item);
if (P.FLink != null )
{
P.BLink.FLink = P.FLink;
P.FLink.BLink = P.BLink;
P.BLink = null ;
P.FLink = null ;
}
}
//查找双向链表最后一个结点元素
private Node FindLast()
{
Node Current = new Node();
Current = Header;
while (!(Current.FLink == null ))
{
Current = Current.FLink;
}
return Current;
}
//逆向打印双向链表
public void PrintReverse()
{
Node Current = new Node();
Current = FindLast();
while (!(Current.BLink == null ))
{
Console.WriteLine(Current.Element);
Current = Current.BLink;
}
}
//打印双向链表
public void Print()
{
Node Current = new Node();
Current = Header;
while (!(Current.FLink == null ))
{
Console.WriteLine(Current.FLink.Element);
Current = Current.FLink;
}
}
}
}
|
链表应用场景
应用场景:集合(动态数组)、贪吃蛇、地图的循环生成、*效果等等,链表可以帮助我们完成很多事情。