链表中的每一个元素都包含一个称为节点的结构,每向链表中增加一个元素,就会产生一个与之相关的节点,每个节点与它相邻的节点相连接(这是基础吧,不过在看c的时候没认真看,呼)。
定义节点类如下(使用了泛型,下面有个简单的具体实例):
class Node<E>{
E element ;
Node<E> next;
public Node(E e){
element = e;
}
}
下面讲解一个储存3个元素的链表的例子,每一个节点储存一个字符串;
1、先声明head(指向第一个节点) 和tai(指向最后一个节点),刚开始时都是null
Node<E> head = null; Node<E> tail = null; //链表为空
2、追加第一个节点
head = new Node<E>("Chicgo"); last = head;
3、追加第二个节点
tail.next = new Node<E>("Denver"); tail = tail.next;
3、追加第三个节点
tail.next = new Node<E>("Dallas"); tail = tail.next;
每一个节点都包含元素和一个名为next的数据域,next指向下一个元素。如果元素是链表中的最后一个元素。则它的next所包含的为null,用这个特性可以检测某个节点是否为最后一个节点,例如下面的遍历程序:
Node current = head; while()current !=null){ System.out.println(current.element); current = current.next; }
下面就结合上面的知识给个简单的int类型事例:
//一个节点类,每一个元素都包含了一个称为节点的结构
public class Node{
int element;
Node next ;
public Node(int n){ //元素赋值
element = n;
}
public static void main(String[] args) {
Node head , tail; //申明head和tail
head = new Node(1); //插入第一个元素
tail = head; //head和tail在一起
System.out.println(head.element); //输出第一个元素
tail.next = new Node(2); //插入第二个元素
tail = tail.next;
tail.next =new Node(3);
tail = tail.next;
Node current = head ;
while (current != null){ //遍历寻遍输出
System.out.print(current.element);
current = current.next;
}
}
}
java中有提供LinkedList的类,可以通过导入 java.util.LinkedList来使用,不过书本上有教我们写一个自己的MyLinkedList,便于理解,这对我们掌握链表还是很有必要的。下面我们可以来仔细研究一下MyLinkedList了,有好多方法,不像MyArrayList容易理解,书本上也只是讲了几个方法,剩下的就自己去理解了,也不是很难,这里讲3个吧,就当练习打字。
(补充:head始终指向链表的第一个节点,而tail则始终指向最后一个节点)
1、实现addFirst(e)方法,就是创建第一个节点:
//创建一个包含e元素节点,并放在第一个节点
public void addFirst(E e) {
Node<E> newNode = new Node<E>(e); // 创建一个的节点
newNode.next = head; //新节点的next数据域指向head
head = newNode; // head 指向新的节点
size++;
if (tail == null) // 若链表为空,则head和tail都指向新节点
tail = head;
}
(书本上的那个图很好看,但是画不下来==)
2、实现add(index,e)方法,当index为0或则是在最后一个元素时就不说了,直接调用方法addFirst(e)或则addLast(e)就行了,若插入到中间时,假设为current和temp节点之间,则首先从head开始前进找到current的next,并被新节点赋给它,在把新节点的next指向temp,画个图就很容易理解了。
public void add(int index, E e) {
if (index == 0) {
addFirst(e);
}
else if (index >= size) {
addLast(e);
}
else {
Node<E> current = head;
for (int i = 1; i < index; i++) {
current = current.next;
}
Node<E> temp = current.next;
current.next = new Node<E>(e);
(current.next).next = temp;
size++;
}
}
3、实现removeLast()方法,如果链表为空就返回null,如果只有一个节点就销毁并且head和tail都变为null,否则最后一个节点销毁,tail指向倒数第二个节点,size减一。
public E removeLast() {
if (size == 0) {
return null;
}
else if (size == 1) {
Node<E> temp = head;
head = tail = null;
size = 0;
return temp.element;
}
else {
Node<E> current = head; //要从head开始遍历,增加了时间
for (int i = 0; i < size - 2; i++) {
current = current.next; //找到倒数第二个节点
}
Node<E> temp = tail; //临时引用temp
tail = current;
tail.next = null;
size--;
return temp.element;
}
}
最后在给出MyLinkedList的实现(仅有部分方法实现,还有部分,做作业):
1 public class MyLinkedList<E> extends MyAbstractList<E> {
2 private Node<E> head, tail;
3
4 //创建默认链表
5 public MyLinkedList() {
6 }
7
8 public MyLinkedList(E[] objects) {
9 super(objects);
10 }
11
12 //获得链表的头
13 public E getFirst() {
14 if (size == 0) {
15 return null;
16 }
17 else {
18 return head.element;
19 }
20 }
21
22 //获得链表的尾
23 public E getLast() {
24 if (size == 0) {
25 return null;
26 }
27 else {
28 return tail.element;
29 }
30 }
31
32 //创建一个包含e元素节点,并放在第一个节点
33 public void addFirst(E e) {
34 Node<E> newNode = new Node<E>(e); // 创建一个的节点
35 newNode.next = head; //新节点的next数据域指向head
36 head = newNode; // head 指向新的节点
37 size++;
38
39 if (tail == null) // 若链表为空,则head和tail都指向新节点
40 tail = head;
41 }
42
43 //创建一个包含e元素节点,并放在最后一个节点
44 public void addLast(E e) {
45 Node<E> newNode = new Node<E>(e);
46
47 if (tail == null) {
48 head = tail = newNode;
49 }
50 else {
51 tail.next = newNode;
52 tail = tail.next;
53 }
54 size++;
55 }
56
57
58 //将一个元素插入到链表的指定下标处
59 public void add(int index, E e) {
60 if (index == 0) {
61 addFirst(e);
62 }
63 else if (index >= size) {
64 addLast(e);
65 }
66 else {
67 Node<E> current = head;
68 for (int i = 1; i < index; i++) {
69 current = current.next;
70 }
71 Node<E> temp = current.next;
72 current.next = new Node<E>(e);
73 (current.next).next = temp;
74 size++;
75 }
76 }
77
78 //删除链表中的的首个元素
79 public E removeFirst() {
80 if (size == 0) {
81 return null;
82 }
83 else {
84 Node<E> temp = head;
85 head = head.next;
86 size--;
87 if (head == null) {
88 tail = null;
89 }
90 return temp.element;
91 }
92 }
93
94 //删除最后一个元素
95 public E removeLast() {
96 if (size == 0) {
97 return null;
98 }
99 else if (size == 1) {
100 Node<E> temp = head;
101 head = tail = null;
102 size = 0;
103 return temp.element;
104 }
105 else {
106 Node<E> current = head; //要从head开始遍历,增加了时间
107 for (int i = 0; i < size - 2; i++) {
108 current = current.next; //找到倒数第二个节点
109 }
110
111 Node<E> temp = tail; //临时引用temp
112 tail = current;
113 tail.next = null;
114 size--;
115 return temp.element;
116 }
117 }
118
119 //删除指定下标的元素
120 public E remove(int index) {
121 if (index < 0 || index >= size) {
122 return null;
123 }
124 else if (index == 0) {
125 return removeFirst();
126 }
127 else if (index == size - 1) {
128 return removeLast();
129 }
130 else {
131 Node<E> previous = head;
132
133 for (int i = 1; i < index; i++) {
134 previous = previous.next;
135 }
136
137 Node<E> current = previous.next;
138 previous.next = current.next;
139 size--;
140 return current.element;
141 }
142 }
143
144 public String toString() {
145 StringBuilder result = new StringBuilder("[");
146
147 Node<E> current = head;
148 for (int i = 0; i < size; i++) {
149 result.append(current.element);
150 current = current.next;
151 if (current != null) {
152 result.append(", "); // 插入歌逗号
153 }
154 else {
155 result.append("]"); // 插入]
156 }
157 }
158
159 return result.toString();
160 }
161
162 //清空
163 public void clear() {
164 head = tail = null;
165 }
166
167
168 /** Return true if this list contains the element o */
169 public boolean contains(E o) {
170 System.out.println("Implementation left as an exercise");
171 return true;
172 }
173
174 /** Return the element from this list at the specified index */
175 public E get(int index) {
176 System.out.println("Implementation left as an exercise");
177 return null;
178 }
179
180 /** Return the index of the head matching element in this list.
181 * Return -1 if no match. */
182 public int indexOf(E o) {
183 System.out.println("Implementation left as an exercise");
184 return 0;
185 }
186
187 /** Return the index of the last matching element in this list
188 * Return -1 if no match. */
189 public int lastIndexOf(E o) {
190 System.out.println("Implementation left as an exercise");
191 return 0;
192 }
193
194 /** Replace the element at the specified position in this list
195 * with the specified element. */
196 public Object set(int index, E o) {
197 System.out.println("Implementation left as an exercise");
198 return null;
199 }
200
201
202 private static class Node<E> {
203 E element;
204 Node<E> next;
205
206 public Node(E element) {
207 this.element = element;
208 }
209 }
210 }
View Code
在附上一个测试程序:
1 public class TestLinkedList {
2 /** Main method */
3 public static void main(String[] args) {
4 // Create a list for strings
5 MyLinkedList<String> list = new MyLinkedList<String>();
6
7 // Add elements to the list
8 list.add("America"); // Add it to the list
9 System.out.println("(1) " + list);
10
11 list.add(0, "Canada"); // Add it to the beginning of the list
12 System.out.println("(2) " + list);
13
14 list.add("Russia"); // Add it to the end of the list
15 System.out.println("(3) " + list);
16
17 list.addLast("France"); // Add it to the end of the list
18 System.out.println("(4) " + list);
19
20 list.add(2, "Germany"); // Add it to the list at index 2
21 System.out.println("(5) " + list);
22
23 list.add(5, "Norway"); // Add it to the list at index 5
24 System.out.println("(6) " + list);
25
26 list.add(0, "Poland"); // Same as list.addFirst("Poland")
27 System.out.println("(7) " + list);
28
29 // Remove elements from the list
30 list.remove(0); // Same as list.remove("Australia") in this case
31 System.out.println("(8) " + list);
32
33 list.remove(2); // Remove the element at index 2
34 System.out.println("(9) " + list);
35
36 list.remove(list.size() - 1); // Remove the last element
37 System.out.println("(10) " + list);
38 }
39 }
View Code
关于MyArrayList和MyLinkedList的方法的复杂度,看下面的图