先来段代码:
package LinkList;
import java.util.Hashtable;
public class LinkList {
Node head = null;
public void addNote(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
return;
}
Node intermediate = head;
while (intermediate.next != null) {
intermediate = intermediate.next;
}
intermediate.next = newNode;
}
public int length() {
int length = 0;
Node tmp = head;
while (tmp != null) {
length++;
tmp = tmp.next;
}
return length;
}
/**
* @param index:delete
* index node.
*
*
*/
public boolean deleteindexnode(int index) {
if (index < 1 || index > length()) {
return false;
}
if (index == 1) {
head = head.next;
return true;
}
int i = 1;
Node prenode = head;
Node currnode = prenode.next;
while (currnode != null) {
if (i == index) {
prenode.next = currnode.next;
}
i++;
prenode = currnode;
currnode = currnode.next;
}
return true;
}
public Node ordlist() {
int temp = 0;
Node cur = head;
Node ne = cur.next;
if (cur == null || ne == null) {
return head;
}
while (cur.next != null) {
while (ne != null) {
if (cur.data > ne.data) {
temp = cur.data;
cur.data = ne.data;
ne.data = temp;
}
ne = ne.next;
}
cur = cur.next;
ne = cur.next;
}
return head;
}
public void printList() {
Node temp = head;
while (temp != null) {
System.out.println(temp.data);
temp = temp.next;
}
}
public Node searchMidNode(){
Node p =this.head;
Node q=this.head;
while (p!=null&&p.next!=null&&p.next.next!=null) {
p = p.next.next;
q = q.next;
}
return q;
}
public void deleteDuplecate() {
Hashtable<Integer, Integer> hashtable = new Hashtable<Integer, Integer>();
Node pre = head;
Node cur = pre.next;
while (cur != null) {
if (hashtable.containsKey(cur.data)) {
pre.next = cur.next;
} else {
hashtable.put(cur.data, 1);
pre = cur;
}
cur = cur.next;
}
}
/*
* public void deleteDuplecatebyErgodic() {
*
* Node cur = head; if (cur == null) { return; } // 外循环 while (cur != null)
* { Node ne = cur; // 内循环 while (ne.next!= null) { if (cur.data ==
* ne.next.data) { ne.next = ne.next.next; } ne = ne.next; } // 内循环结束 cur =
* cur.next; } // 外循环结束
*
* }
*/
public void reverseList() {
Node pReverseHead = head;
Node pNode = head;
Node pPrev = null;
while (pNode != null) {
Node pNext = pNode.next;
if (pNext == null) {
pReverseHead = pNode;
}
pNode.next = pPrev;
pPrev = pNode;
pNode = pNext;
}
this.head = pReverseHead;
}
public void printListReversely(Node head){
if (head!=null) {
printListReversely(head.next);
System.out.println(head.data);
}
}
public static void main(String[] args) {
LinkList list = new LinkList();
list.addNote(1);
list.addNote(8);
list.addNote(4);
list.addNote(6);
list.addNote(4);
list.addNote(8);
list.addNote(8);
list.addNote(7);
list.addNote(1);
System.out.println("length:" + list.length());
System.out.println("before:");
list.printList();
list.printListReversely(list.head);
System.out.println("逆序输出");
System.out.println("下面是中间结点:");
System.out.println(list.searchMidNode().data);
// list.printList();
// list.ordlist();
// System.out.println("Then");
// list.printList();
System.out.println("Reverse:");
list.reverseList();
list.printList();
// System.out.println("Final");
// list.deleteDuplecate();
// list.printList();
}
}
class Node {
Node next;
int data;
public Node(int data) {
this.data = data;
}
}
上面这段代码包含了链表的一些基本操作。
如何在不知道头指针的情况下删除指定结点?分两种情况来讨论:
1.如果待删除的结点是尾结点,那么无法删除。
2.如果待删除的结点不是尾部节点,那么可以通过交换该结点与其后继结点的值,然后删除后继结点。
下面是具体的代码实现:
public Boolean deleteNode(Node node) {
if (node.next == null) {
return false;
}
int temp = node.data;
node.data = node.next.data;
node.next.data = temp;
node.next = node.next.next;
return true;
}
如何判断2个链表结点相交?如果2个链表相交,则最后一个交点处肯定是尾结点(如果不是尾结点,那么肯定存在某个分叉的结点,而该结点会有2个指向,这显然是不可以的)。所以只要判断尾结点是否相同即可。下面是实现:
public Boolean isIntersect(Node p,Node q){
if (p==null||q==null) {
return false;
}
Node ptail=p;
while (ptail.next!=null) {
ptail=ptail.next;
}
Node qtail = q;
while (qtail.next!=null) {
qtail=qtail.next;
}
return qtail==ptail;//不需要使用data,因为都是尾结点,所以qtail.next和ptail.next都是null,实际比较的还是data。
}
继续讨论,如果2个链表相交,那么如何寻找他们相交的第一个结点呢,接下来分析一下:如果给定2个相交的链表,那么这2个链表肯定有长有短,假定长链表的长度为a,短链表的长度为b,则长链表从a-b处与短链表同时遍历比较即可。这样即可找到第一个,甚至可以找到任意的一个他们共有的结点。下面是具体实现:
public Node searchFirstCommon(Node p, Node q) {
// 首先判断是否相交,相交才能执行寻找第一个结点的操作。
if (!this.isIntersect(p, q)) {
return null;
}
int plenth = 0;
int qlenth = 0;
while (p != null) {// 找长度
plenth++;
p = p.next;
}
while (q != null) {// 找长度
qlenth++;
q = q.next;
}
// 将长链表“缩短”再遍历
Node pNode = p;
Node qNode = q;
if (plenth > qlenth) {
int t = plenth - qlenth;
while (t != 0) {
pNode = pNode.next;
t--;
}
} else {
int t = qlenth - plenth;
while (t != 0) {
qNode = qNode.next;
t--;
}
}
// 接下来同时遍历。
while (pNode != qNode) {
pNode = pNode.next;
qNode = qNode.next;
}
return qNode;
}
上述算法只需要分别遍历一次两个链表,时间复杂度为O(len1+len2),如果调用之前我们写过的统计长度和判断相交的方法,需要遍历2遍链表(每个方法遍历一遍,而我们这样写,在遍历一遍的同时做了两件事情:统计长度和得到尾结点,从而判断是否相交,不过这样做耦合性较差)。因此效率偏低。但是那样做会使得代码简洁,可用性强。
参考书:《JAVA程序员面试笔试宝典》 -----何昊、薛鹏、叶向阳 编著