-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathLinkedIntList.java
160 lines (139 loc) · 4.46 KB
/
LinkedIntList.java
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
151
152
153
154
155
156
157
158
159
160
// LinkedIntList provides an implementation of the IntList interface backed by
// a doubly-linked list with dummy header nodes at the front and back. This
// will provide O(1) performance for adding at the front or back of the list
// and removing values while iterating over the list. All of the iterator's
// methods are O(1). Methods like get and set will be O(n) for values in the
// middle of the list.
import java.util.*;
public class LinkedIntList extends AbstractIntList {
private ListNode front; // first value in the list
private ListNode back; // last value in the list
private int size; // current number of elements
// post: constructs an empty list
public LinkedIntList() {
front = new ListNode(0);
back = new ListNode(0);
clear();
}
// post: returns the current number of elements in the list
public int size() {
return size;
}
// pre : 0 <= index < size()
// post: returns the integer at the given index in the list
public int get(int index) {
checkIndex(index);
ListNode current = nodeAt(index);
return current.data;
}
// post: appends the given value to the end of the list
public void add(int value) {
add(size, value);
}
// pre: 0 <= index <= size()
// post: inserts the given value at the given index, shifting subsequent
// values right
public void add(int index, int value) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("index: " + index);
ListNode current = nodeAt(index - 1);
ListNode newNode = new ListNode(value, current.next, current);
current.next = newNode;
newNode.next.prev = newNode;
size++;
}
// pre : 0 <= index < size()
// post: replaces the integer at the given index with the given value
public void set(int index, int value) {
checkIndex(index);
ListNode current = nodeAt(index);
current.data = value;
}
// pre : 0 <= index < size()
// post: removes value at the given index, shifting subsequent values left
public void remove(int index) {
checkIndex(index);
ListNode current = nodeAt(index - 1);
current.next = current.next.next;
current.next.prev = current;
size--;
}
// post: list is empty
public void clear() {
front.next = back;
back.prev = front;
size = 0;
}
// post: returns an iterator for this list
public Iterator<Integer> iterator() {
return new LinkedIterator();
}
// pre : 0 <= index < size()
// post: returns the node at a specific index. Uses the fact that the list
// is doubly-linked to start from the front or the back, whichever
// is closer.
private ListNode nodeAt(int index) {
ListNode current;
if (index < size / 2) {
current = front;
for (int i = 0; i < index + 1; i++)
current = current.next;
} else {
current = back;
for (int i = size; i >= index + 1; i--)
current = current.prev;
}
return current;
}
private static class ListNode {
public int data; // data stored in this node
public ListNode next; // link to next node in the list
public ListNode prev; // link to previous node in the list
// post: constructs a node with given data and null links
public ListNode(int data) {
this(data, null, null);
}
// post: constructs a node with given data and given links
public ListNode(int data, ListNode next, ListNode prev) {
this.data = data;
this.next = next;
this.prev = prev;
}
}
private class LinkedIterator implements Iterator<Integer> {
private ListNode current; // location of next value to return
private boolean removeOK; // whether it's okay to remove now
// post: constructs an iterator for the given list
public LinkedIterator() {
current = front.next;
removeOK = false;
}
// post: returns true if there are more elements left, false otherwise
public boolean hasNext() {
return current != back;
}
// pre : hasNext() (throws NoSuchElementException if not)
// post: returns the next element in the iteration
public Integer next() {
if (!hasNext())
throw new NoSuchElementException();
int result = current.data;
current = current.next;
removeOK = true;
return result;
}
// pre : next() has been called without a call on remove (i.e., at most
// one call per call on next; throws IllegalStateException if
// not)
// post: removes the last element returned by the iterator
public void remove() {
if (!removeOK)
throw new IllegalStateException();
ListNode prev2 = current.prev.prev;
prev2.next = current;
current.prev = prev2;
size--;
removeOK = false;
}
}
}