package com.johnChnia.coding2017.basic.linklist;
import com.johnChnia.coding2017.basic.List;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Created by john on 2017/3/9.
*
* @// TODO: 学会多线程后,实现Iterator 的 remove 方法
*/
public class LinkedList<E> implements List<E> {
private Node<E> first = null;
private int size = 0;
/**
* Constructs an empty list.
*/
public LinkedList() {
}
private static class Node<T> {
T element;
Node<T> next;
Node<T> prev;
}
/**
* Appends the specified element to the end of this list.
*
* @param element element to be appended to this list
*/
public void add(E element) {
Node<E> newNode = new Node<>();
if (first == null) {
addWhenListIsEmpty(newNode, element);
return;
}
Node<E> last = first;
while (last.next != null)
last = last.next;
last.next = newNode;
newNode.prev = last;
newNode.next = null;
newNode.element = element;
size++;
}
private void addWhenListIsEmpty(Node<E> newNode, E element) {
first = newNode;
first.element = element;
first.next = null;
first.prev = null;
size++;
}
/**
* Inserts the specified element at the beginning of this list.
*
* @param element the element to add
*/
public void addFirst(E element) {
Node<E> newNode = new Node<>();
if (first == null) {
addWhenListIsEmpty(newNode, element);
return;
}
newNode.next = first;
newNode.prev = null;
newNode.element = element;
first.prev = newNode;
first = newNode;
size++;
}
/**
* Appends the specified element to the end of this list.
*
* @param element element to be appended to this list.
*/
public void addLast(E element) {
add(element);
}
/**
* Inserts the specified element at the specified position in this list.
* Shifts the element currently at that position (if any) and any
* subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted.
* @param element element to be inserted.
* @throws RuntimeException if list size less than 2.
*/
public void add(int index, E element) {
if (size() < 2)
throw new RuntimeException("list size should greater than or equal to 2");
isElementIndex(index);
if (index == 0) {
addFirst(element);
return;
} else {
Node<E> temp = new Node<>();
Node<E> temp2 = first;
for (int i = 0; i < index; i++) {
temp2 = temp2.next;
}
temp2.prev.next = temp;
temp.prev = temp2.prev;
temp.next = temp2;
temp2.prev = temp;
temp.element = element;
}
size++;
}
/**
* remove last element in the list.
*
* @throws RuntimeException if the list is empty.
*/
public E removeLast() {
if (size == 0)
throw new RuntimeException("linkList size should greater than or equal to 1");
E element;
Node<E> next = first.next;
if (next == null) {
element = first.element;
first = null;
} else {
Node<E> last = first;
while (last.next != null)
last = last.next;
last.prev.next = null;
element = last.element;
last = null; // help GC
}
size--;
return element;
}
/**
* @param index
* @return
* @// TODO: 2018/3/14 if i am happy, i will implement it right now!
*/
public E remove(int index) {
return null;
}
/**
* Removes and returns the first element from this list.
*
* @return the first element from this list
*/
public E removeFirst() {
Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
E element = f.element;
Node<E> next = first.next;
first.element = null;
first.next = null; // help GC
first = next;
if (next != null) {
next.prev = null;
}
size--;
return element;
}
/**
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
*/
public E get(int index) {
checkElementIndex(index);
Node<E> node = first;
if (index == 0) {
return first.element;
}
for (int i = 0; i < index; i++) {
node = node.next;
}
return node.element;
}
/**
* Returns the first element in this list.
*
* @return the first element in this list
* @throws NoSuchElementException if this list is empty
*/
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.element;
}
/**
* Returns the number of elements in this list.
*
* @return the number of elements in this list
*/
public int size() {
return size;
}
@Override
public Iterator<E> iterator() {
return new Itr();
}
@Override
public boolean contains(Object o) {
return false;
}
private class Itr implements Iterator<E> {
/**
* Index of element to be returned by subsequent call to next.
*/
int cursor = 0;
@Override
public boolean hasNext() {
return cursor != size();
}
@Override
public E next() {
int i = cursor;
if (i >= size) {
throw new NoSuchElementException();
}
E next = get(i);
cursor = i + 1;
return next;
}
}
private void checkElementIndex(int index) {
if (!isElementIndex(index)) {
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
}
/**
* Tells if the argument is the index of an existing element.
*/
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(first.element);
Node<E> temp = first;
while (temp.next != null) {
temp = temp.next;
sb.append("→");
sb.append(temp.element);
}
return sb.toString();
}
/**
* 把该链表逆置
* 例如链表为 3->7->10 , 逆置后变为 10->7->3
*/
public void reverse() {
Node<E> next;
Node<E> current = first;
for (int i = 0; i < size; i++) {
next = current.next;
current.next = current.prev;
current.prev = next;
if (next != null) {
current = next;
}
}
first = current;
}
/**
* 删除一个单链表的前半部分
* 例如:list = 2->5->7->8 , 删除以后的值为 7->8
* 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10
*/
public void removeFirstHalf() {
int index = size() / 2;
Node<E> current = first;
Node<E> prev;
for (int i = 0; i < index; i++) {
prev = current;
current = current.next;
delete(prev);
}
current.prev = null;
first = current;
size = size - index;
}
/**
* 从第i个元素开始, 删除length 个元素 , 注意i从0开始
*
* @param i
* @param length
*/
public void remove(int i, int length) {
checkElementIndex(i);
if (length + i > size()) {
throw new IllegalArgumentException("Length + i should less than or equal " + size());
}
Node<E> head = first;
Node<E> tail = first;
if (i == 0 && length == size()) {
first = null;
} else if (i == 0 && length < size()) {
for (int j = 0; j < length; j++) {
head = head.next;
}
head.prev = null;
first = head;
} else {
for (int j = 0; j < i; j++) {
head = head.next;
}
head = head.prev;
for (int j = 0; j < length + i; j++) {
tail = tail.next;
}
head.next = tail;
if (tail != null) {
tail.prev = head;
}
}
size = size - length;
}
/**
* 假定当前链表和list均包含已升序排列的整数
* 从当前链表中取出那些list所指定的元素
* 例如当前链表 = 11->101->201->301->401->501->601->701
* listB = 1->3->4->6
* 返回的结果应该是[101,301,401,601]
*
* @param list
*/
public int[] getElements(LinkedList list) {
int[] newArray = new int[list.size()];
Node mapNode = list.first;
Node valueNode = this.first;
int indexOfList = 0;
int indexOfArray = 0;
while (mapNode != null && valueNode != null) {
int mapValue = (int) mapNode.element;
if (mapValue == indexOfList) {
newArray[indexOfArray] = (int) valueNode.element;
mapNode = mapNode.next;
valueNode = valueNode.next;
indexOfArray++;
} else {
valueNode = valueNode.next;
}
indexOfList++;
}
return newArray;
}
/**
* 已知链表中的元素以值递增有序排列,并以单链表作存储结构。
* 从当前链表中中删除在listB中出现的元素
*
* @param list
*/
public void subtract(LinkedList<E> list) {
Node pNode = first;
Node qNode = list.first;
Node prev = null;
Node deletedNode;
while (pNode != null && qNode != null) {
if ((int) qNode.element < (int) pNode.element) {
qNode = qNode.next;
} else if ((int) qNode.element > (int) pNode.element) {
prev = pNode;
pNode = pNode.next;
} else {
if (prev == null) { // 头结点
first = pNode.next;
} else {
prev.next = pNode.next;
}
deletedNode = pNode;
pNode = pNode.next;
qNode = qNode.next;
delete(deletedNode);
size--;
}
}
}
private void delete(Node node) {
node.element = null;
node.prev = null;
node.next = null;
}
/**
* 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。
* 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同)
*/
public void removeDuplicateValues() {
Node<E> current = first;
Node<E> next = current.next;
while (next != null) {
if (current.element == next.element) {
current.next = next.next;
if (next.next != null) {
next.next.prev = current;
}
delete(next);
next = current.next;
size--;
} else {
current = current.next;
next = next.next;
}
}
}
/**
* 已知链表中的元素以值递增有序排列,并以单链表作存储结构。
* 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素)
*
* @param min
* @param max
*/
public void removeRange(int min, int max) {
Node current = first;
Node prev = null;
Node deletedNode;
while (current != null) {
if ((int) current.element >= max) {
break;
}
if ((int) current.element > min && (int) current.element < max) {
if (prev == null) { // 头结点
first = current.next;
} else {
prev.next = current.next;
}
deletedNode = current;
current = current.next;
delete(deletedNode); // help gc
size--;
} else {
prev = current;
current = current.next;
}
}
}
/**
* 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同)
* 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列
*
* @param list
*/
public LinkedList intersection(LinkedList list) {
LinkedList l = new LinkedList();
Node pNode = first;
Node qNode = list.first;
while (pNode != null && qNode != null) {
if ((int) pNode.element < (int) qNode.element) {
pNode = pNode.next;
} else if ((int) pNode.element > (int) qNode.element) {
qNode = qNode.next;
} else {
l.add(pNode.element);
pNode = pNode.next;
qNode = qNode.next;
}
}
return l;
}
/**
* Constructs an IndexOutOfBoundsException detail message.
* Of the many possible refactorings of the error handling code,
* this "outlining" performs best with both server and client VMs.
*/
private String outOfBoundsMsg(int index) {
return "Index: " + index + ", Size: " + size;
}
}