这里使用两种方式,
一个是直接从头日后遍历 -------> 迭代
一个是从最后一个往前遍历 -----> 递归指针
定义三个变量:pPre pNext pNow
pPre表示当前节点的前一个地址,pNext表示当前节点的下一个地址,pNow表示当前节点的地址。code
反转的核心:就是把 pNow的next指针,指向 pPre递归
由于反转以后,pNow的next原来的值会丢,因此在反转以前,要用pNext把原来的值保存一下。
反转以后,要处理下一个节点,而本节点就是下一个节点的前一个节点,因此用pPre把当前节点地址保存一下。变量
struct ListNode* reverseList(struct ListNode* head){ struct ListNode *pstPre = NULL; struct ListNode *pstNow = head; struct ListNode *pstNext = NULL; while (NULL != pstNow) { pstNext = pstNow->next; // 先保存一下当前节点的next指针 pstNow->next = pstPre; // 作反转 pstPre = pstNow; // 更新pstPre指针 pstNow = pstNext; // 继续作下一个节点的反转 } return pstPre; }
递归的话,不太好理解,先上代码,看着代码来理解:List
struct ListNode* reverseList(struct ListNode* head){ struct ListHode *pstNewHead = NULL; if (head == NULL || head->next == NULL) // 若是链表为空,或者是最末端节点,则直接返回当前节点地址 { return head; } else { pstNewHead = reverseList(head->next); // 返回新链表头节点 head->next->next = head; // 这里完成反转 head->next = NULL; return pstNewHead; } }
递归写法的关键是:head->next->next = head 这句代码中,
head 是谁,head->next 是谁,head->next->next 又是谁!遍历
能够从后往前理解,假设有三个节点,为 1 -> 2 -> 3,链表
最后一次:当head为节点2时,入参为传入节点3,节点3的next为NULL,返回节点3的地址。next
此时:head指向节点2,pstNewHead指向节点3,
-----> 获得:head->next 指向节点3,head->next->next 就至关于节点3的next,
因此:执行完 "head->next->next = head"以后,就至关于把节点3的next指向了节点2,完成一个反转。
而节点2的next指针已经没用了(本来节点2的next指向了节点3),直接指向NULL。
上面部分实现了节点3与节点2的反转,并此时pstNewHead指向了节点3。while
再继续。
上面返回pstNewHead为节点3的地址,此时入参的head为1(由于以前head为节点2,返回调用者的时候,是head->next为节点2,因此这里调用者为节点1),
因此,head->next为2,head->next->next 就至关因而节点2的next,因此执行完 "head->next->next = head"以后,就至关于把节点2的next指向了节点1。
而节点1原来的next没用了(本来节点1的next指向了节点2),直接指向NULL,这里就至关因而链表尾部。
而后返回pstNewHead。
其实这里pstNewHead只赋值过一次,以后从未改变,一直指向了最一开始的节点3。co