单链表的概念很容易理解,就是单向链表的意思。
下面直接给出实现:
import java.util.Arrays;
import java.util.Random;
import java.util.StringJoiner;
/**
* 单链表的实现.
*/
public class LinkedList<Z> {
private static class Node<K> {
K data;
Node<K> next;
}
private final Node<Z> head = new Node<>();
private int length = 0;
public LinkedList() {
head.data = null;
head.next = null;
}
public int size() {
return length;
}
public boolean isEmpty() {
return length == 0;
}
public boolean add(Z data) {
return insert(0, data);
}
public boolean addLast(Z data) {
return insert(length, data);
}
public boolean set(int index, Z data) {
int pos = -1;
Node<Z> h = head;
while (h.next != null) {
if (index - 1 == pos) {
break;
}
h = h.next;
pos++;
}
if (pos == length) {
return false;
}
Node<Z> old = h.next;
Node<Z> young = new Node<>();
young.data = data;
h.next = young;
//noinspection ConstantConditions
young.next = old.next;
old.data = null;
return true;
}
public boolean replace(int index, Z data) {
int pos = -1;
Node<Z> h = head;
while (h.next != null) {
if (index == pos) {
break;
}
h = h.next;
pos++;
}
if (pos == length) {
return false;
}
h.data = data;
return true;
}
// a [k] b c d
public boolean insert(int index, Z data) {
if (index < 0 || index > length) {
return false;
}
int pos = -1;
Node<Z> h = head;
while (h.next != null) {
if (index - 1 == pos) {
break;
}
h = h.next;
pos++;
}
if (pos == length) {
return false;
}
Node<Z> old = h.next;
Node<Z> young = new Node<>();
young.data = data;
h.next = young;
young.next = old;
length++;
return true;
}
public int indexOf(Z data) {
int pos = -1;
if (data == null) {
return pos;
}
Node<Z> h = head;
while (h.next != null) {
if (data.equals(h.data)) {
break;
}
h = h.next;
pos++;
}
return pos;
}
public Z get(int index) {
if (index < 0 || index >= length) {
return null;
}
int pos = -1;
Node<Z> h = head;
while (h.next != null) {
if (index == pos) {
break;
}
h = h.next;
pos++;
}
if (pos == length) {
return null;
}
return h.data;
}
public boolean remove(Z data) {
return remove(indexOf(data));
}
public boolean removeLast() {
return remove(length - 1);
}
public boolean removeFirst() {
return remove(0);
}
public boolean remove(int index) {
if (index < 0 || index >= length) {
return false;
}
int pos = -1;
Node<Z> h = head;
while (h.next != null) {
if (index - 1 == pos) {
break;
}
h = h.next;
pos++;
}
if (pos == length) {
return false;
}
// now h' pos == index-1
Node<Z> target = h.next;
//noinspection ConstantConditions
h.next.data = null; // remove target
h.next = target.next;
length -= 1;
return true;
}
public boolean clear() {
while (length > 0) {
removeFirst();
}
return true;
}
public void reverse() {
if (isEmpty()) {
return;
}
Object[] zs = new Object[size()];
Node<Z> h = head;
int pos = -1;
while (h.next != null) {
h = h.next;
pos++;
zs[pos] = h.data;
}
System.out.println("in reverse---" + Arrays.toString(zs));
// now zs has all the elements of this linked list.
h = head;
for (int i = zs.length - 1; i >= 0; --i) {
// like add(zs[i]);
Node<Z> node = new Node<>();
node.data = (Z) zs[i];
node.next = null;
h.next = node;
h = h.next;
}
}
public void listReverse() {
// _ 3 8 9 7 6
// + 8 3
Node<Z> rh = new Node<>();
Node<Z> next;
Node<Z> cur = head.next;
while (cur != null) {
// System.out.println("--- " + cur.data);
next = cur.next;
cur.next = rh.next;
rh.next = cur;
cur = next; // move origin linked list
}
head.next = rh.next;
}
/**
* @param order 0== no sort; 1== 3,2,1 , -1 == 1,2,3.
*/
public <T extends Comparable<T>> LinkedList<T> merge(LinkedList<T> another, int order) {
LinkedList<T> list = new LinkedList<>();
if (0 == order) {
for (int i = 0; i < size(); ++i) {
list.addLast((T) get(i));
}
if (another != null) {
for (int i = 0; i < another.size(); ++i) {
list.addLast(another.get(i));
}
}
} else {
for (int i = 0; i < size(); ++i) {
// list.addLast((T) get(i));
T data = (T) get(i);
int j;
for (j = 0; j < list.size(); ++j) {
T z = list.get(j);
if (order < 0
? z.compareTo(data) > 0 :
z.compareTo(data) < 0) {
break;
}
}
list.insert(j, data);
}
if (another != null) {
for (int i = 0; i < another.size(); ++i) {
T data = another.get(i);
int j;
for (j = 0; j < list.size(); ++j) {
T z = list.get(j);
if (order < 0
? z.compareTo(data) > 0 :
z.compareTo(data) < 0) {
break;
}
}
list.insert(j, data);
}
}
}
return list;
}
public String format() {
int pos = -1;
StringBuilder sb = new StringBuilder(getClass().getSimpleName() + ": {");
Node<Z> h = head;
while (h != null) {
Z data = h.data;
if (pos != -1) {
sb.append("[").append(pos).append("]=").append(data).append(", ");
}
h = h.next;
pos++;
}
int last = sb.lastIndexOf(", ");
if (last != -1) {
sb.delete(last, last + 2);
}
sb.append("} | size=").append(length).append(" ##|");
return sb.toString();
}
public void show() {
System.out.println(format());
}
@Override
public String toString() {
return new StringJoiner(", ",
LinkedList.class.getSimpleName() + "[", "]")
.add(format()).toString();
}
public static void main(String[] args) {
// big();
LinkedList<Integer> list = new LinkedList<>();
Random random = new Random(189);
for (int i = 0; i < 5; ++i) {
int data = random.nextInt(100);
int pos;
for (pos = 0; pos < list.size(); ++pos) {
Integer value = list.get(pos);
if (value > data) {
break;
}
}
list.insert(pos, data);
// System.out.println("each insert: " + list.format());
}
System.out.println("self : " + list);
// list.reverse();
// System.out.println("reversed--- " + list);
list.listReverse();
System.out.println("list-reverse:" + list);
LinkedList<Integer> integerLinkedList = new LinkedList<>();
for (int i = 0; i < 3; ++i) {
integerLinkedList.add(random.nextInt(55));
}
System.out.println(integerLinkedList);
LinkedList<Integer> merge = list.merge(integerLinkedList, -1);
System.out.println("merged: " + merge);
}
private static void big() {
LinkedList<Integer> list = new LinkedList<>();
list.show();
Random random = new Random();
list.add(random.nextInt(100));
list.show();
list.add(random.nextInt(100));
list.addLast(random.nextInt(100));
list.show();
list.removeLast();
list.show();
list.removeFirst();
list.show();
boolean insert = list.insert(8, random.nextInt(100));
System.out.println("insert=" + insert + "," + list.format());
list.clear();
System.out.println("cleared? " + list.format());
for (int i = 0; i < 5; ++i) {
list.addLast(random.nextInt(100));
}
list.show();
list.set(0, -1024);
list.set(3, 1024);
list.set(4, -2048);
list.show();
list.clear();
System.out.println("##############");
for (int i = 0; i < 5; ++i) {
int data = random.nextInt(300);
int pos;
for (pos = 0; pos < list.size(); ++pos) {
Integer value = list.get(pos);
if (value > data) {
break;
}
}
list.insert(pos, data);
System.out.println("each insert: " + list.format());
}
list.show();
list.insert(3, 99);
int index = list.indexOf(99);
System.out.println("index==" + index);
list.show();
list.remove((Integer) 99);
list.set(2, 345);
list.show();
boolean replace = list.replace(2, -544);
System.out.println("replace--" + replace + " , " + list);
System.out.println("$$$$: " + list);
}
}
然后说一下这个反转的思路。
先看一下反转的实现:
public void listReverse() {
// _ 3 8 9 7 6
// + 8 3
Node<Z> rh = new Node<>();
Node<Z> next;
Node<Z> cur = head.next;
while (cur != null) {
// System.out.println("--- " + cur.data);
next = cur.next;
cur.next = rh.next;
rh.next = cur;
cur = next; // move origin linked list
}
head.next = rh.next;
}
反转的代码并不多,直接分析一下这里的实现思路:
- 因为是单链表,所以,只能去单向的遍历;那反转的话,就是相当于把链表的连接方向反转一下。大体上,可以认为是,将遍历取出来的节点依次插入到一个空节点的后面,每次都是插入到这个位置,这样,这个空节点形式的链表就是反转之后的链表了。
- 具体实现大概是:
- 先定义一个临时的节点作为反转时的头结点;然后遍历这个单链表,然后就可以拿到每个节点了。拿到这个节点呢,就把这个节点直接插入到临时头结点的后面。
- 不过,要注意,首先,既然是遍历这个链表,就要去不断的执行
cur = cur.next
这样的代码;但是,这个cur
,我们要重新定义它的链接,要把它放到这个临时头结点的后面去,就要尽早的切断cur
跟原链表直接的链接关系。这个切断很简单,直接就是通过局部变量next = cur.next; ...; cur = next;
这样的方式就可以了。 - 那么,在
...
里面,就要去把这个cur
插入到这个临时头结点的后面去了;同时还得注意,如果只是每次都把cur
插入到临时头结点的后面,那么,这个临时头结点形成的链表只会有一个元素,这个元素就是不断刷新的cur
; - 所以,在把这个
cur
插入到临时头结点后面的同时,要处理好cur.next
的指向,这个指向呢因为是遍历的单链表,其实很不好处理,因为你不知道cur.prev
是什么; - 不过因为这个临时头结点
rh
的存在,rh.next
一定是上一个cur
,所以,直接先让cur.next
指向rh.next
然后再把rh.next
更新成新的cur
; 这样一来,通过遍历原始的链表就可以做到每次得到的节点都被插入到临时头结点之后,并且链接到临时头结点原来的下一个节点之前。 - 最后,遍历结束了,这个
rh
其实就是反转之后的链表了;这时候让原始的头结点链接到rh
的下一个节点,这个原始的链表就被反转完成了。这个rh
也就不再需要了。