单链表—反转链表
-
例题:
链表:1->2->3->4->5->null 反转后:5->4->3->2->1->null
一、反转单链表逻辑分析
/*
链表反转后:
原链表头结点指向 null ,原链表尾结点 n 指向原链表第 n-1 个结点,
原链表第 n-1 个结点指向原链表第 n-2 个结点,
以此类推,原链表第二个结点指向原链表第一个结点。
1 -> 2 -> 3 -> 4 -> 5 -> null
5 -> 4 -> 3 -> 2 -> 1 -> null
实现方法:
1. 迭代法
2. 递归法
*/
// 提前创建一个链表
// 1. 定义 node 结点
const node = (val=null,next=null) => {
return {
value:val,
next:next
}
}
// 2. 定义链表
var node4 = node('5'),
node3 = node('4',node4),
node2 = node('3',node3),
node1 = node('2',node2),
head = node('1',node1);
// 遍历输出链表
function printList(head){
var headNode = head , list =[] ;
while(headNode){
list.push(headNode)
headNode = headNode.next;
}
console.log(list);
}
console.log("原始链表数据:")
printList(head);
二、迭代法实现链表反转
/*
1. 迭代法(前置条件: 链表不为一个元素,且结点不为空;)
从第一个节点开始修改,直到结束 , 通过 while 循环遍历,将此次遍历结点指向上一个节点,若为头结点则指向 null。
*/
function reverseList(head){
// 链表为 null 或 只有一个节点
if(!head || !head.next){return head}
var temporaryHead = head; // 获取头结点
var reverseNewListHead = null; // 用于存储链表翻转之后的新的头结点 && 作为遍时链表的头结点
while(temporaryHead){
// 1. 临时存储原始链表的下一个结点(因为下面操作会操作 temporaryHead.next 的值)
var next = temporaryHead.next;
//console.log("1.next:",next)
// 2. 更新当前结点的下一个结点为新链表的头结点
temporaryHead.next = reverseNewListHead;
//console.log("2.temporaryHead.next:",temporaryHead.next)
// 3. 更新当前结点为新链表的头结点
reverseNewListHead = temporaryHead;
//console.log("3.reverseNewListHead:",reverseNewListHead)
// 4. 重新获取原始链表要更新的结点
temporaryHead = next;
//console.log("4.temporaryHead:",temporaryHead ? temporaryHead : null)
}
return reverseNewListHead;
}
console.log("翻转链表数据(迭代法):")
printList( reverseList(head))
- 迭代法代码运行分析
// 迭代法
// Runing:
// while(temporaryHead)
/*
var next = temporaryHead.next;
↓
→ node1 -> node2 -> node3 -> node4 -> null
temporaryHead.next = reverseNewListHead;
↓
→ null -> head -> node1 -> node2 -> node3
reverseNewListHead = temporaryHead;
↓
→ head -> node1 -> node2 -> node3 -> node4
temporaryHead = next;
↓
→ node1 -> node2 -> node3 -> node4 -> null
*/
三、递归法实现链表反转
/*
2. 递归法(递归边界: 链表不为一个元素,且结点不为空;)
直接递归至链表最后一个节点,从末尾向前开始逻辑操作。
*/
function iteratorList(head){
// 判断链表是否为空或者是否只有一个元素 设置递归边界
if( !head || !head.next ) return head;
// 直接跑到末尾
var next = head.next ;
var reverseNewListHead = reverseList(next);
// 在没有到达最后一个结点之前,不会开始逻辑操作
next.next = head;
head.next = null;
console.log("head.next",head.next)
return reverseNewListHead;
}
console.log("翻转链表数据(递归法):")
iteratorList(head);
printList(node4);
- 递归法代码运行分析:
// 递归法
// Running:
/*
递归至末尾:
next = head.next;
var reverseNewListHead = reverseList(next);
next:
node1 -> node2 -> node3 -> node4
开始逻辑操作:
1. next.next = head;
next = node4 时 , head = node3
node4.next = node3
next = node3 时 , head = node2
node3.next = node3
next = node2 时 , head = node1
node2.next = node3
next = node1 时 , head = head
node1.next = head
2. head.next = null;
主要功能: 原始列表 head 的 next 为 null
*/
TIp:通过迭代法翻转链表所进行的操作的是原链表