|
| 1 | +package me.ramswaroop.common; |
| 2 | + |
| 3 | +import java.util.NoSuchElementException; |
| 4 | + |
| 5 | +import static java.lang.System.out; |
| 6 | + |
| 7 | +/** |
| 8 | + * Created by IntelliJ IDEA. |
| 9 | + * |
| 10 | + * @author: ramswaroop |
| 11 | + * @date: 6/16/15 |
| 12 | + * @time: 1:00 PM |
| 13 | + */ |
| 14 | +public class CircularSingleLinkedList<E extends Comparable<E>> implements LinkedList<E> { |
| 15 | + |
| 16 | + public SingleLinkedNode<E> head; |
| 17 | + public int size; |
| 18 | + |
| 19 | + @Override |
| 20 | + public boolean add(E item) { |
| 21 | + SingleLinkedNode<E> newNode = new SingleLinkedNode<>(item, head); |
| 22 | + if (head == null) { // list empty |
| 23 | + head = newNode; |
| 24 | + newNode.next = head; |
| 25 | + } else { // add to the end of list |
| 26 | + SingleLinkedNode<E> curr = head; |
| 27 | + while (curr.next != head) { |
| 28 | + curr = curr.next; |
| 29 | + } |
| 30 | + curr.next = newNode; |
| 31 | + } |
| 32 | + size++; |
| 33 | + return true; |
| 34 | + } |
| 35 | + |
| 36 | + @Override |
| 37 | + public boolean add(int index, E item) { |
| 38 | + isPositionIndex(index); |
| 39 | + |
| 40 | + if (index == 0) { // add at first |
| 41 | + addFirst(item); |
| 42 | + } else { // add at any other location |
| 43 | + SingleLinkedNode<E> nodeAtPrevIndex = getPredecessorNode(index); |
| 44 | + SingleLinkedNode<E> newNode = new SingleLinkedNode<>(item, nodeAtPrevIndex.next); |
| 45 | + nodeAtPrevIndex.next = newNode; |
| 46 | + size++; |
| 47 | + } |
| 48 | + return true; |
| 49 | + } |
| 50 | + |
| 51 | + @Override |
| 52 | + public void addFirst(E item) { |
| 53 | + SingleLinkedNode<E> newNode = new SingleLinkedNode<>(item, head), node; |
| 54 | + if (head == null) { // empty linked list |
| 55 | + newNode.next = newNode; |
| 56 | + } else { |
| 57 | + node = getNode(size - 1); |
| 58 | + node.next = newNode; |
| 59 | + } |
| 60 | + head = newNode; |
| 61 | + size++; |
| 62 | + } |
| 63 | + |
| 64 | + @Override |
| 65 | + public void addLast(E item) { |
| 66 | + add(item); |
| 67 | + } |
| 68 | + |
| 69 | + @Override |
| 70 | + public void clear() { |
| 71 | + // Clearing all of the links between nodes is "unnecessary", but: |
| 72 | + // - helps a generational GC if the discarded nodes inhabit |
| 73 | + // more than one generation |
| 74 | + // - is sure to free memory even if there is a reachable Iterator |
| 75 | + for (SingleLinkedNode<E> node = head; node != null; ) { |
| 76 | + SingleLinkedNode<E> next = node.next; |
| 77 | + node.item = null; |
| 78 | + node.next = null; |
| 79 | + node = next; |
| 80 | + } |
| 81 | + head = null; |
| 82 | + size = 0; |
| 83 | + } |
| 84 | + |
| 85 | + @Override |
| 86 | + public LinkedList<E> clone() { |
| 87 | + return null; |
| 88 | + } |
| 89 | + |
| 90 | + @Override |
| 91 | + public boolean contains(E item) { |
| 92 | + return getNode(item) != null; |
| 93 | + } |
| 94 | + |
| 95 | + @Override |
| 96 | + public E get(int index) { |
| 97 | + return getNode(index).item; |
| 98 | + } |
| 99 | + |
| 100 | + @Override |
| 101 | + public E getFirst() { |
| 102 | + isLinkedListEmpty(); |
| 103 | + return head.item; |
| 104 | + } |
| 105 | + |
| 106 | + @Override |
| 107 | + public E getLast() { |
| 108 | + return getNode(size - 1).item; |
| 109 | + } |
| 110 | + |
| 111 | + @Override |
| 112 | + public E remove() { |
| 113 | + isLinkedListEmpty(); |
| 114 | + |
| 115 | + E item = head.item; |
| 116 | + // last node should point to new head |
| 117 | + SingleLinkedNode<E> lastNode = getNode(size - 1); |
| 118 | + lastNode.next = head.next; |
| 119 | + head = (head.next != head) ? head.next : null; |
| 120 | + size--; |
| 121 | + return item; |
| 122 | + } |
| 123 | + |
| 124 | + @Override |
| 125 | + public E remove(int index) { |
| 126 | + isLinkedListEmpty(); |
| 127 | + |
| 128 | + SingleLinkedNode<E> prevNode = getPredecessorNode(index), |
| 129 | + delNode, |
| 130 | + lastNode; |
| 131 | + if (prevNode == null) { // index = 0 |
| 132 | + delNode = head; |
| 133 | + head = (head.next != head) ? head.next : null; |
| 134 | + size--; |
| 135 | + return delNode.item; |
| 136 | + } else { |
| 137 | + delNode = prevNode.next; |
| 138 | + prevNode.next = delNode.next; |
| 139 | + // last node should point to new head |
| 140 | + lastNode = getNode(size - 1); |
| 141 | + lastNode.next = head.next; |
| 142 | + head = head.next; |
| 143 | + size--; |
| 144 | + return delNode.item; |
| 145 | + } |
| 146 | + } |
| 147 | + |
| 148 | + @Override |
| 149 | + public boolean removeItem(E item) { |
| 150 | + isLinkedListEmpty(); |
| 151 | + |
| 152 | + if (!contains(item)) return false; |
| 153 | + |
| 154 | + SingleLinkedNode<E> prevNode = getPredecessorNode(item), |
| 155 | + lastNode; |
| 156 | + if (prevNode == null) { // index = 0 |
| 157 | + head = (head.next != head) ? head.next : null; |
| 158 | + size--; |
| 159 | + } else { |
| 160 | + prevNode.next = prevNode.next.next; |
| 161 | + // last node should point to new head |
| 162 | + lastNode = getNode(size - 1); |
| 163 | + lastNode.next = head.next; |
| 164 | + head = head.next; |
| 165 | + size--; |
| 166 | + } |
| 167 | + return true; |
| 168 | + } |
| 169 | + |
| 170 | + @Override |
| 171 | + public E set(int index, E item) { |
| 172 | + SingleLinkedNode<E> node = getNode(index); |
| 173 | + node.item = item; |
| 174 | + return node.item; |
| 175 | + } |
| 176 | + |
| 177 | + @Override |
| 178 | + public int size() { |
| 179 | + return size; |
| 180 | + } |
| 181 | + |
| 182 | + @Override |
| 183 | + public void printList() { |
| 184 | + SingleLinkedNode<E> curr = head; |
| 185 | + out.print("["); |
| 186 | + if (curr == null) { |
| 187 | + out.println("]"); |
| 188 | + return; |
| 189 | + } |
| 190 | + while (curr.next != head) { |
| 191 | + out.print(curr.item + ","); |
| 192 | + curr = curr.next; |
| 193 | + } |
| 194 | + out.println(curr.item + "]"); |
| 195 | + } |
| 196 | + |
| 197 | + public static <E extends Comparable<E>> CircularSingleLinkedList<E> getLinkedList(SingleLinkedNode<E> node) { |
| 198 | + CircularSingleLinkedList<E> linkedList = new CircularSingleLinkedList<>(); |
| 199 | + // set head |
| 200 | + linkedList.head = node; |
| 201 | + // set size |
| 202 | + SingleLinkedNode<E> curr = node; |
| 203 | + while (curr != linkedList.head) { |
| 204 | + linkedList.size++; |
| 205 | + curr = curr.next; |
| 206 | + } |
| 207 | + return linkedList; |
| 208 | + } |
| 209 | + |
| 210 | + private SingleLinkedNode<E> getPredecessorNode(int index) { |
| 211 | + return index > 0 ? getNode(index - 1) : null; |
| 212 | + } |
| 213 | + |
| 214 | + private SingleLinkedNode<E> getPredecessorNode(E item) { |
| 215 | + SingleLinkedNode<E> prev = null; |
| 216 | + SingleLinkedNode<E> curr = head; |
| 217 | + if (item == null) { |
| 218 | + while (curr != head) { |
| 219 | + if (curr.item == item) { // when item is null, use == rather than equals() |
| 220 | + return prev; |
| 221 | + } |
| 222 | + prev = curr; |
| 223 | + curr = curr.next; |
| 224 | + } |
| 225 | + } else { |
| 226 | + while (curr != head) { |
| 227 | + if (curr.item.equals(item)) { |
| 228 | + return prev; |
| 229 | + } |
| 230 | + prev = curr; |
| 231 | + curr = curr.next; |
| 232 | + } |
| 233 | + } |
| 234 | + return null; |
| 235 | + } |
| 236 | + |
| 237 | + public SingleLinkedNode<E> getNode(int index) { |
| 238 | + isElementIndex(index); |
| 239 | + |
| 240 | + SingleLinkedNode<E> curr = head; |
| 241 | + int i = 0; |
| 242 | + while (i < index) { |
| 243 | + curr = curr.next; |
| 244 | + i++; |
| 245 | + } |
| 246 | + return curr; |
| 247 | + } |
| 248 | + |
| 249 | + public SingleLinkedNode<E> getNode(E item) { |
| 250 | + SingleLinkedNode<E> curr = head; |
| 251 | + if (item == null) { |
| 252 | + while (curr != head) { // when item is null, use == rather than equals() |
| 253 | + if (curr.item == item) { |
| 254 | + return curr; |
| 255 | + } |
| 256 | + curr = curr.next; |
| 257 | + } |
| 258 | + } else { |
| 259 | + while (curr != head) { |
| 260 | + if (curr.item.equals(item)) { |
| 261 | + return curr; |
| 262 | + } |
| 263 | + curr = curr.next; |
| 264 | + } |
| 265 | + } |
| 266 | + return null; |
| 267 | + } |
| 268 | + |
| 269 | + private void isLinkedListEmpty() { |
| 270 | + if (head == null) { |
| 271 | + throw new NoSuchElementException("LinkedList empty"); |
| 272 | + } |
| 273 | + } |
| 274 | + |
| 275 | + /** |
| 276 | + * Tells if the argument is the index of an existing element. |
| 277 | + */ |
| 278 | + private void isElementIndex(int index) { |
| 279 | + if (index < 0 || index >= size) { |
| 280 | + throw new IndexOutOfBoundsException("Index [" + index + "] must be less than size [" + size + "]"); |
| 281 | + } |
| 282 | + } |
| 283 | + |
| 284 | + /** |
| 285 | + * Tells if the argument is the index of a valid position for an |
| 286 | + * iterator or an add operation. |
| 287 | + */ |
| 288 | + private void isPositionIndex(int index) { |
| 289 | + if (index < 0 || index > size) { |
| 290 | + throw new IndexOutOfBoundsException("Index [" + index + "] must be less than or equal to size [" + size + "]"); |
| 291 | + } |
| 292 | + } |
| 293 | +} |
0 commit comments