设计链表

  • 哨兵节点

    哨兵节点在树和链表中被广泛用作伪头、伪尾等,通常不保存任何数据。我我们将此使用伪头简化插入和删除。

  • 双链表的双向搜索

    我们可以从头部或尾部进行搜索。

单链表

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
public class SinglyLinkedList<E> {

private int size;
private Node<E> head;

public SinglyLinkedList() {
head = new Node<>(null, null);
}

/**
* addAtIndex,addAtHead,addAtTail
*
* 找到要插入位置的前驱节点
* 通过改变 next 来插入节点
*
* @author chengxudong chengxudong@microwu.com
* @date 2021/8/21 7:17
*
* @param
* @return void
*/
public void addAtIndex(int index, E e) {
indexCheck(index);

if (e == null) {
throw new IllegalArgumentException();
}

Node<E> prev = head;
for (int i = 0; i < index; i++) {
prev = prev.next;
}

prev.next = new Node<>(e, prev.next);
size++;

}

public void addAtHead(E e) {
addAtIndex(0, e);
}

public void addAtTail(E e) {
addAtIndex(size, e);
}

public E deleteAtIndex(int index) {
indexCheck(index);

Node<E> prev = head;
for (int i = 0; i < index; i++) {
prev = prev.next;
}

Node<E> node = prev.next;
prev.next = node.next;

size--;
return node.e;
}

public E get(int index) {
indexCheck(index);

Node<E> node = head;
for (int i = 0; i < index + 1; i++) {
node = node.next;
}

return node.e;
}

private void indexCheck(int index) {
if (index < 0 || index >size) {
throw new IllegalArgumentException();
}
}

private static class Node<E> {
E e;
Node<E> next;

Node(E e, Node<E> next) {
this.e = e;
this.next = next;
}
}

@Override
public String toString() {
Node<E> node = head;
StringJoiner sj = new StringJoiner(",");
for (int i = 0; i < size; i++) {
node = node.next;
sj.add(String.valueOf(node.e));
}
return sj.toString();
}

public static void main(String[] args) {
SinglyLinkedList<Integer> list = new SinglyLinkedList<>();
list.addAtHead(1);
list.addAtTail(3);
list.addAtIndex(1, 2);
System.out.println(list);
System.out.println(list.get(1));
System.out.println(list.deleteAtIndex(1));
System.out.println(list);
System.out.println(list.get(1));

}
}

双链表

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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
public class DoublyLinkedList<E> {

private int size;
private Node<E> head;
private Node<E> tail;

public DoublyLinkedList() {
head = new Node<>(null, null, null);
tail = new Node<>(null, null, null);;

head.next = tail;
tail.prev = head;
}

public void addAtIndex(int index, E e) {
indexCheck(index);

Node<E> prev;
if (index < size - index) {
// 从头遍历
prev = head;
for (int i = 0; i < index; i++) {
prev = prev.next;
}
} else {
// 从尾遍历
prev = tail;
for (int i = 0; i < size - index; i++) {
prev = prev.prev;
}
}

Node<E> node = new Node<>(e, prev, prev.next);
prev.next = node;
node.prev = prev;

size++;
}

/**
* 双向链表的头插入和尾插入不能使用 addAtIndex
*
* @author chengxudong chengxudong@microwu.com
* @date 2021/8/21 8:19
*
* @param e
* @return void
*/
public void addAtHead(E e) {
Node<E> node = new Node<>(e, head, head.next);
head.next.prev = node;
head.next = node;

size++;
}

public void addAtTail(E e) {
Node<E> node = new Node<>(e, tail.prev, tail);
tail.prev.next = node;
tail.prev = node;

size++;
}

public E deleteAtIndex(int index) {
indexCheck(index);

Node<E> prev;
if (index < size - index) {
// 从头遍历
prev = head;
for (int i = 0; i < index; i++) {
prev = prev.next;
}
} else {
// 从尾遍历
prev = tail;
for (int i = 0; i < size - index - 1; i++) {
prev = prev.prev;
}
}

Node<E> next = prev.next;
next.next.prev = prev;
prev.next = next.next;

size--;
return next.e;
}

public E get(int index) {
indexCheck(index);

Node<E> node;
if (index < size - index) {
node = head;
for (int i = 0; i < index + 1; i++) {
node = node.next;
}
} else {
node = tail;
for (int i = 0; i < size - index; i++) {
node = node.prev;
}
}
return node.e;
}

private void indexCheck(int index) {
if (index < 0 || index >size) {
throw new IllegalArgumentException();
}
}

@Override
public String toString() {
Node<E> node = head;
StringJoiner sj = new StringJoiner(",");
for (int i = 0; i < size; i++) {
node = node.next;
sj.add(String.valueOf(node.e));
}
return sj.toString();
}

private static class Node<E> {
E e;
Node<E> prev;
Node<E> next;

Node(E e, Node<E> prev, Node<E> node) {
this.e = e;
this.prev = prev;
this.next = node;
}
}

public static void main(String[] args) {
DoublyLinkedList<Integer> list = new DoublyLinkedList<>();
list.addAtHead(1);
list.addAtTail(3);
list.addAtIndex(1, 2);
System.out.println(list);
System.out.println(list.get(1));
System.out.println(list.deleteAtIndex(1));
System.out.println(list);
System.out.println(list.get(1));

}
}