反转链表问题
反转一个单链表。
问题分析
最最直接的做法就是创建一系列新节点,然后按顺序把原来链表的值赋值给它们,后面的结点依次指向前面的结点就完事了。但是这种做法浪费空间内存,如果我们直接在原链表上进行反转就可以大大节省空间内存。
简单来说就是将原链表的next指针的指向反转方向,就可以实现链表的反转。
实现next指针反转的操作
- 定义两个指针per、post,两个指针在链表中相邻,per在前,post在后(注意:这里的前后是按原链表的指向,左边是前,右边是后)
- post.next=pre; 实现post和per之间的指针反转
- 两指针不断向后移动,完成每一个指针的反转,最后per指针指向反转后链表的头结点
下面介绍两种实现方式
递归法
使用递归函数实现两指针的移动
public ListNode reverseList(ListNode head) {
//初始化per为null,per指向头结点
return reverse(null,head);
}
public ListNode reverse(ListNode pre,ListNode post){
//post为null时表示反转结束,结束递归,返回头结点
if(post==null){
return pre;
}
ListNode temp=post.next; //记录post的下一个结点
post.next=pre; //反转
return reverse(post,temp); //递归调用,per移动一个位置成为post,post移动到下一个结点
}
双指针法
定义两个指针后通过循环不断向后移动,进行反转操作
public ListNode reverseList2(ListNode head){
//两相邻节点
ListNode post=head; //后面的节点,从头结点开始
ListNode pre=null; //前面的结点,后面的结点从头结点开始,所以前面的结点从null开始
ListNode temp; //后面的结点指针要指向前面的结点,所以用来保存后面结点再后面的结点
while(post!=null){
temp=post.next; //先记录后面结点再后面的结点
post.next=pre; //两相邻结点指针反转
//两相邻结点同时向后移动,继续反正下一个指针
pre=post;
post=temp;
}
//反转后最后的结点就是头结点,返回头结点
return pre;
}