一、单向链表反转
/**
* 这里要注意,我的head不能作为开始的第一个结点,我的head只是一个起点的哨兵标识
* 如果将head作为第一个结点开始计算,
* 假如单向链表结构为: head -> a -> b -> c lest = c;
* 那么第一次运算之后head -> null
* 第二次运算 a -> head
* 第三次运算 b -> a
* 第四次运算 c -> b
* 跳出while循环,我们的操作是
* head -> c
* 此时就形成了一个循环,
* a -> head -> c -> b -> a -> head -> c ........ 如果我们要打印这个单向链表就容易出现StackOverflowError!
*/
Node<E> begin = null;
Node<E> model = this.head.getNext();
this.last = model;
Node<E> end = model.getNext();
while (true){
model.setNext(begin);
if(end == null){
break;
}
begin = model;
model = end;
end = end.getNext();
}
this.head.setNext(model);
return;
}
注意这个方法是放在我之前的LinkNode类中。博客地址
这里使用的是3个指针,每循环一次,3个指针都移动一次,并且改变model结点的指针方法,这种单向链表反转也叫做原地反转!
二、判断链表中是否有环。
思路:
1、快慢指针方法,使用两个指针,同时进行移动,如果链表中有环,那么这两个指针会先后进入环中,因为一个走的慢,一个走的快,总有一此循环会导致这两个指针是指向同一个结点!
2、足迹法,首先建立一个Map用来存储链表中的结点,然后遍历这个链表,每遍历一次就把结点信息保存到Map中,如果Map中存储了重复了元素则说明链表中有环!
我实现了快慢指针法如下:
/**
* 快慢指针法判断链表中是否有环
* @return
*/
public boolean isHaveLoop(){
if(this == null){
return false;
}
Node<E> p = this.head.getNext();//第一个结点
Node<E> q = this.head.getNext().getNext();//如果有的话是第二个结点
//如果q为空,那么这个单向链表只有一个结点,肯定不会形成环
//如果q不为空,并且q的下一个结点为空,那么有两个结点并且第二个结点指向null,肯定也不会形成环
while (q != null && q.getNext() != null){
p = p.getNext();
q = q.getNext().getNext();
if(q == null){
return false;
}else if(p == q){
return true;
}
}
return false;
}
注意:这个方法也是放在了我上一篇博客中的LinkNode类中。博客地址
三、使用递归来实现两个有序单向链表合并
public class LinkNodes {
/**
* 使用递归来实现两个有序单向链表合并
* @param node1
* @param node2
* @return
*/
public static Node<Integer> mergeLinkNode(Node<Integer> node1,Node<Integer> node2){
//当node1和node2同时为null时,说明到node1和node2的最后一个结点。
if(node1 == null && node2 == null){
return null;
}
//node1为null则不用再比较大小了
if(node1 == null){
return node2;
}
if(node2 == null){
return node1;
}
Node<Integer> node = new Node<>();
if(node1.getE() > node2.getE()){
node = node2;
node.setNext(mergeLinkNode(node1,node2.getNext()));
}else if(node1.getE() < node2.getE()){
node = node1;
node.setNext(mergeLinkNode(node1.getNext(),node2));
}else{
node = node1;
node.setNext(mergeLinkNode(node1.getNext(),node2.getNext()));
}
return node;
}
}
注意:这个是我新建了一个工具类,为了方便起见,我将泛型执行为了Integer
下面是我的测试
public class TestLinkNode {
public static void main(String[] args) {
Node<Integer> node = new Node<>(1);
Node<Integer> node1 = new Node<>(2);
Node<Integer> node2 = new Node<>(3);
Node<Integer> node3 = new Node<>(4);
Node<Integer> node4 = new Node<>(5);
Node<Integer> node5 = new Node<>(6);
Node<Integer> node6 = new Node<>(7);
Node<Integer> node7 = new Node<>(8);
node.setNext(node2);
node2.setNext(node4);
node4.setNext(node6);
node6.setNext(node7);
System.out.println("----------第一个有序单向链表------------");
System.out.println(node);
node1.setNext(node3);
node3.setNext(node5);
System.out.println("----------第二个有序单向链表------------");
System.out.println(node1);
Node<Integer> node8 = LinkNodes.mergeLinkNode(node, node1);
System.out.println("----------两个有序单向链表合并之后------------");
System.out.println(node8);
}
}
输出:
----------第一个有序单向链表------------
Node{next=Node{next=Node{next=Node{next=Node{next=null, e=8}, e=7}, e=5}, e=3}, e=1}
----------第二个有序单向链表------------
Node{next=Node{next=Node{next=null, e=6}, e=4}, e=2}
----------两个有序单向链表合并之后------------
Node{next=Node{next=Node{next=Node{next=Node{next=Node{next=Node{next=Node{next=null, e=8}, e=7}, e=6}, e=5}, e=4}, e=3}, e=2}, e=1}
Process finished with exit code 0
结束!