1.判断两个单链表是否相交,若相交输出相交节点的值,否则返回NULL
/**
* 两个单链表是否相交,我们先要得到两个链表的长度,计算出长度的差size,接着先让长链表从头节点走size个,
* 然后两个链表开始同时遍历,若可以遇到相同的节点,说明链表相交,否则遍历到null,说明链表没有相交
* @param link
* @return
*/
public T isLinkIntersect(Link<T> link) {
Entry<T> cur1 = this.headEntry;
Entry<T> cur2 = link.headEntry;
// 先求出两个链表的长度
int len1 = 0;
int len2 = 0;
while (cur1 != null) {
cur1 = cur1.next;
len1++;
}
while (cur2 != null) {
cur2 = cur2.next;
len2++;
}
// 再找出是否存在相交节点
cur1 = this.headEntry;
cur2 = link.headEntry;
if (len1 > len2) { // 链表1比较长
int size = len1 - len2;
for (int i = 0; i < size; ++i) {
cur1 = cur1.next;
}
} else if (len1 < len2) { // 链表2比较长
int size = len2 - len1;
for (int i = 0; i < size; ++i) {
cur2 = cur2.next;
}
}
while (cur1 != null && cur2 != null) {
if (cur1 == cur2) { // 两个指针指向同一个节点,说明链表相交
return cur1.getValue();
}
cur1 = cur1.next;
cur2 = cur2.next;
}
return null;
}
2.判断单链表是否有环,若存在环输出环的入口节点
/**
* 1.判断单链表是否有环
* @return
*/
public Entry<T> isLoop() {
Entry<T> fast = headEntry, slow = headEntry;
// 使用快慢指针解决该问题
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
return fast;
}
}
return null;
}
/**
* 2.若存在环,输出环的入口节点
* @return
*/
public Entry<T> getIntersectEntry() {
Entry<T> meet = isLoop();
if (meet == null) {
return null;
}
//fast从第一个节点开始走,slow从快慢指针相交的节点开始走,它们相遇的时候,就是环的入口节点
Entry<T> slow = meet;
Entry<T> fast = headEntry;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
/**
* 判断单链表是否有环,若有环输出入环节点的值,若没有环返回null
* @return
*/
public T getLinkCircleVal() {
Entry<T> slow = this.headEntry;
Entry<T> fast = this.headEntry;
// 使用快慢指针解决该问题
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
break;
}
}
if (fast == null) {
return null;
} else {
//fast从第一个节点开始走,slow从快慢指针相交的节点开始走,它们相遇的时候,就是环的入口节点
fast = this.headEntry;
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
return slow.value;
}
}
3.两个单链表有序,将其合并成为一个有序单链表
/**
* 两个单链表有序,将其合并成为一个有序单链表
* @param link
*/
public Entry<T> merge(Link<T> link) {
Entry<T> p = new Entry(-1);//自定义实现的单链表不带头结点
Entry<T> q = p;//返回q,便于查看合并后的结果
Entry<T> p1 = this.headEntry;
Entry<T> p2 = link.headEntry;
// 比较p1和p2节点的值,把值小的节点挂在p的后面
while (p1 != null && p2 != null) {
if (p1.value.compareTo(p2.value) >= 0) {
p.next = p2;
p2 = p2.next;
} else {
p.next = p1;
p1 = p1.next;
}
p = p.next;
}
if (p1 != null) {// 链表1还有剩余节点
p.next = p1;
}
if (p2 != null) {// 链表2还有剩余节点
p.next = p2;
}
return q;
}
4.单链表逆置
/**
* 逆置单链表,思想是从链表第二个节点开始采用头插法重新连接节点
*/
public void reverse() {
if (this.headEntry == null) {
return;
}
//从单链表第二个节点开始逆置
Entry<T> cur = this.headEntry.next;
this.headEntry.next = null;
this.tailEntry = this.headEntry;//更新尾结点
Entry<T> post = null;
Entry<T> pre = this.headEntry;
while (cur != null) {
post = cur.next;
cur.next = pre;
pre = cur;
cur = post;
}
this.headEntry = pre;//更新头结点
}
5. 单链表的倒数第K个节点
/**
* 输出单链表中倒数第k个节点的值
*
* @param k
* @return
*/
public T getLastOfK(int k) {
int linkLength = getLength(headEntry);
if (k <= 0 || k > linkLength) {
return null;
}
Entry<T> cur1 = this.headEntry;
Entry<T> cur2 = this.headEntry;
// cur1指向第一个节点,cur2指向正数第k个节点
for (int i = 0; i < k; i++) {
cur2 = cur2.next;
if (cur2 == null) {
return null;
}
}
// 当cur2到达末尾节点时,cur1指向的就是倒数第k个节点
while (cur2 != null) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1.value;
}