递归实现逆序输出单链表
我们可以采用递归的方式实现逆序输出单链表的操纵,因为head节点的next节点是指向head的下一个节点,所以我们从头开始遍历链表,并让head往后走,当head.next为空时,此时已经走到链表结尾处,输出节点值。重复以上操作,即可实现链表逆序输出。
代码如下:
public static <T> void reversePrintList(SingleLinkedList<T>.Node<T> head){
//递归终止条件
if(head==null){
//处理办法
return;
}
//提取重复逻辑,缩小问题规模
reversePrintList(head.next);
System.out.println(head.data);
}
逆置单链表
在这道题里我们需要定义三个节点来进行操作,prev用来表示当前节点的上一个节点,current用来表示当前节点,next用来表示当前节点的下一个节点。
当当前节点不为空时,我们开始将当前节点与前一个节点的指向转变,如果next节点为空,那说明已经走到原来链表的末尾位置,此时将当前节点作为逆置后新链表的头节点。
直到当前节点为空,逆置完成。
具体代码:
public static <T> SingleLinkedList<T>.Node<T> reverseList(SingleLinkedList<T>.Node<T> head){
SingleLinkedList<T>.Node<T> prev = null;//当前节点的上一个
SingleLinkedList<T>.Node<T> current = head;//当前节点
SingleLinkedList<T>.Node<T> next = null;//当前节点的下一个
SingleLinkedList<T>.Node<T> newHead = null;//逆置后链表的头节点
while(current!=null){
next = current.next;
if(next == null){
newHead = current;
}
//改变当前节点与之前一个节点之间的指向
current.next = prev;
prev = current;
current = next;
}
return newHead;
}
合并两个有序的链表,保证合并后的链表依然有序
对于合并两个有序链表,我们可以先定义一个新链表的头节点和一个临时引用,先进行比较,哪一个链表的首位数小就把那一个作为新链表的头节点。
随后,分别比较两个链表后面数据的大小,借用临时引用,把较小的一个接入新链表。
此时,若一个链表为空,那可将剩下链表这部分的数据直接链入新链表。
代码如下:
public static <T extends Comparable<T>> SingleLinkedList<T>.Node<T> mergrLinkedList(
SingleLinkedList<T>.Node<T> head1,SingleLinkedList<T>.Node<T> head2){
SingleLinkedList<T>.Node<T> newHead = null;//确定新链表的头节点
if(head1.data.compareTo(head2.data)<0){
newHead = head1;
head2 = head1.next;
}else {
newHead = head2;
head2 = head2.next;
}
//临时引用在新链表中从前往后去跑
SingleLinkedList<T>.Node<T> tmp = newHead;
while (head1!=null&&head2!=null){
if(head1.data.compareTo(head2.data)<0){
tmp.next = head1;
head1 = head1.next;
}else {
tmp.next = head2;
head2 = head2.next;
}
tmp = tmp.next;
}
if(head1 == null){
tmp.next = head2;
}
if(head2 == null){
tmp.next = head1;
}
return newHead;
}
判断两个链表的相交结点
因为两个链表的长度不同,所以我们先获取两个链表的长度,让长链表的引用先走其插值的长度。
随后,让两个引用同时走,若两个引用相等了,那么说明此时该引用所指向的节点即为相交结点。
代码如下:
public static <T> SingleLinkedList<T>.Node<T> commonNode2(SingleLinkedList<T> list1,
SingleLinkedList<T> list2){
if(list1.head == null||list2.head == null) return null;
//计算两个链表的差值
int length1 = getlength(list1.head);
int length2 = getlength(list2.head);
int lengthDif = Math.abs(length1-length2);
SingleLinkedList<T>.Node<T> longHead =list1.head;
SingleLinkedList<T>.Node<T> shortHead =list2.head;
//长链表先走其差值
if(length1<length2){
longHead = list1.head;
shortHead = list2.head;
}
for(int i=0;i<lengthDif;i++){
longHead = longHead.next;
}
//长链表和短链表开始同时走,当两个引用的相等的时候,此时该引用所指向的节点就是相交结点
while (shortHead!=longHead){
longHead = longHead.next;
shortHead = shortHead.next;
}
return longHead;
}
判断单链表是否有环,同时得到环的入口节点是哪个
判断是否有环,我们可以定义两个引用,一个慢引用、一个快引用。
让慢引用一次走两步,慢引用一次走一步。当他们在环中相遇时的节点即为环的入口节点。
代码如下:
public static <T> boolean isRing(SingleLinkedList<T> list){
//快 、慢引用 快引用一次走两步 慢引用一次走一步
SingleLinkedList<T>.Node<T> slow = list.head;
SingleLinkedList<T>.Node<T> fast = list.head;
while (fast!=null&&slow!=null&&fast.next!=null){
if(fast == slow){
//表示在环中相遇,fast/slow所指向的节点为相遇节点
return true;
}
slow = slow.next;
fast = fast.next.next;
}
return false;
}