这几天在看算法基础,链表部分再练练手,单向链表的反转是一个比较考验思维缜密的技巧点。先在纸上画一下单向链表的结构,分析一下指向问题,基本得出解决思路(解决思路不复杂,但是要小心处理各个指针(引用)的指向关系):
1,基本得出解决思路
1,通过while循环遍历链表。
2,每次遍历都要分析出三层节点关系:父节点、子节点,孙节点。每次遍历都将子节点的next指针(引用)指向父节点。
3,遍历结束之后,获得当前链表的尾节点。
4,修正头节点head的next指针为null,变为尾节点用。
5,将头节点head指向尾节点。
注意:
特殊处理一下没有数据(head节点为空),和只有一个数据(head节点的next为空)
Talk is cheap, show me the code:
// 单向链表练习
class Node{
constructor(data){
this.data = data;
this.next = null;
}
}
class LinkTableSingle{
constructor(){
this.head = null;
}
add(data){
const n = new Node(data);
if(!this.head){
this.head = n;
return this;
}
let currentNode = this.head;
while(currentNode.next !== null){
currentNode = currentNode.next
}
currentNode.next = n;
return this;
}
// 挑战单向链表的反转,这里算三个指针(引用的移动问题吧)
reverse(){
let parentNode = this.head;
// 没有节点或者只有一个节点,不需要反转
if(parentNode ===null || parentNode.next ===null){
return;
}
let childNode = parentNode.next;
while(childNode){
let grandChildNode = childNode.next;
childNode.next = parentNode;
parentNode = childNode;
childNode = grandChildNode;
}
this.head.next = null;
// 把head节点指向最后一个节点,如果sub节点已经为null了,那么此时的parent节点就是最后一个节点。
this.head = parentNode;
}
}
// 测试一下:
function test(){
const lt = new LinkTableSingle();
lt.add("a");
lt.add("b");
lt.add("c");
lt.add("d");
lt.add("e");
lt.reverse();
console.log(lt);
}
test()
2,图解反转过程:
高清图:https://www.processon.com/view/link/6120c902f346fb785d212b9e
先直观的看看添加完数据的链表和反转后的链表图
直观的看完单向链表存储的数据及反转后的效果后,咱们看看具体步骤:
步骤1:通过while循环找到第一个父节点、子节点、孙节点,技巧:定义一个变量,引用子节点的next,就是孙节点。
步骤2:反转子节点的next,将其指向改为父节点:
步骤3:将当前子节点作为下一次循环的父节点;当前孙节点作为下一次的子节点,继续下一次循环。
步骤4:循环遍历完整个链表,此时父节点指向了最后一个节点。
步骤5:修正头节点和尾节点:
this.head.next = null;
this.head = parentNode;
3,备注上画图地址:
https://www.processon.com/view/link/6120c902f346fb785d212b9e
画图不容易,写代码和调试花了半个多小时。画图花了两个多小时,也算值得。这次更清晰了。