Java数据结构和算法(一)线性结构之单链表

时间:2023-03-10 00:27:16
Java数据结构和算法(一)线性结构之单链表

Java数据结构和算法(一)线性结构之单链表

     prev                 current              next
-------------- -------------- --------------
| value | next | -> | value | next | -> | value | next |
-------------- -------------- --------------

单链表的结构如上:最后一个节点的 next=null。下面看一下代码。

(1) 链表的基本操作

public class Node<E> {

    private E value;
private Node next; public Node(E value) {
this.value = value;
} // 追加到最后一个元素
public Node append(Node node) {
Node tail = tail();
tail.next(node);
return this;
} // 删除指定的节点
public void remove(Node node) {
Node prev = prev(node);
if (prev != null) {
prev.next = node.next;
}
} // 节点总数
public int size() {
int size = 1;
Node current = this;
while (current.next != null) {
size++;
current = current.next;
}
return size;
} // 查找指定节点的上一个节点
public Node prev(Node node) {
Node prev = this;
while (prev != null) {
if (prev.next == node) {
return prev;
}
prev = prev.next;
}
return null;
} // 查找尾节点,单链表 tail.next=null
public Node tail() {
Node tail = this;
while (tail.next != null) {
tail = tail.next;
}
return tail;
} // 设置当前节点的下一个节点
public void next(Node next) {
// 设置该节点的后继节点
next.next = this.next;
// 将该节点设置为当前节点的前驱节点
this.next = next;
} public Node next() {
return next;
} public E getValue() {
return value;
} public void setValue(E value) {
this.value = value;
}
}

(2) 取出中间节点

偶数节点取中间两个节点的前一个节点,奇数节点取正中间的节点

public Node mid() {
Node stepOneNode = this;
Node stepTwoNode = this;
while (stepTwoNode != null) {
stepTwoNode = stepTwoNode.next;
if (stepTwoNode != null) {
stepTwoNode = stepTwoNode.next;
if (stepTwoNode != null) {
stepOneNode = stepOneNode.next;
}
}
}
return stepOneNode;
}

(3) 链表反转

public Node reverse() {
Node prev = null;
Node next = null;
Node current = this;
while (current != null) {
next = current.next;
current.next = prev;
prev = current;
current = next;
}
return prev;
}

测试一把:

public void test1() {
Node n1 = new Node(1);
Node n2 = new Node(2);
Node n3 = new Node(3); n1.append(n2).append(n3);
Assert.assertEquals(3, n1.next().next().getValue());
Assert.assertEquals(3, n1.tail().getValue());
Assert.assertEquals(2, n1.prev(n3).getValue());
Assert.assertEquals(3, n1.size()); n1.remove(n2);
Assert.assertEquals(3, n1.next().getValue());
Assert.assertEquals(1, n1.mid().getValue()); n1.next(n2);
Assert.assertEquals(3, n1.next().next().getValue());
Assert.assertEquals(2, n1.mid().getValue()); Node reverse = n1.reverse();
Assert.assertEquals(3, reverse.getValue());
Assert.assertEquals(2, reverse.next().getValue());
Assert.assertEquals(1, reverse.next().next().getValue());
}

(4) 有序链表的合并

两个有序链表合并后还是有序的,代码如下:

// 有序链表合并,两个链表均升序排列,最终的结果也升序排列
public static Node merge(Node<Integer> node1, Node<Integer> node2) {
if (node1 == null || node2 == null) {
return node1 == null ? node2 : node1;
} Node<Integer> head = node1.value < node2.value ? node1 : node2;
Node<Integer> cur1 = head == node1 ? node1 : node2; // 小
Node<Integer> cur2 = head == node1 ? node2 : node1; // 大 Node prev = null; // curl1 的前驱节点,小
while (cur1 != null && cur2 != null) {
if (cur1.value < cur2.value) {
prev = cur1;
cur1 = cur1.next;
} else {
// 将 curl2 插入到 prev 和 curl1 之间
Node tmp = cur2.next;
cur2.next = cur1;
prev.next = cur2;
prev = cur2;
cur2 = tmp;
}
}
prev.next = cur1 == null ? cur2 : cur1;
return head;
} // 有序链表合并,两个链表均升序排列,最终的结果也升序排列
public static Node mergeRecurse(Node<Integer> node1, Node<Integer> node2) {
if (node1 == null || node2 == null) {
return node1 != null ? node1 : node2;
}
Node head = null;
if (node1.value > node2.value) {
head = node2;
head.next = mergeRecurse(node1, node2.next);
} else {
head = node1;
head.next = mergeRecurse(node1.next, node2);
}
return head;
}

测试:

public void mergeTest() {
Node n1 = new Node(1);
// 省略...
Node n6 = new Node(6); n1.append(n3).append(n5);
n2.append(n4).append(n6); Node merge1 = Node.merge(n1, n2);
//Node merge1 = Node.mergeRecurse(n1, n2);
Assert.assertEquals(6, merge1.size());
Assert.assertEquals(2, merge1.next().getValue());
}

每天用心记录一点点。内容也许不重要,但习惯很重要!

相关文章