单链表的逆转:(头尾互换)
1 迭代反转(适用于反转不带头节点的链表)
从当前链表的首元节点开始,一直遍历到链表的最后一个节点,这期间逐个改变所遍历到的节点的指针域,另其指向前一个节点。
方法是借用三个指针,
首先三个指针 begin mid end
分别指向 null 第一个节点 第二个节点
然后遍历就是各向后移动一个节点,直至mid指向链表中最后一个节点(此时end 为null)。
代码:head为无头节点链表的头指针
link * iteration_reserve (link * head){
if(head == null || head->next == null ){
return head;
}
else{
link * begin = null;
link* mid = head;
link* end = head->next;
// 遍历
while(1){
mid->next = begin;
if(end == null){
break;
}
begin = mid ;
mid = end;
end = end->next;
}
// 最后修改head头指针的指向
head = mid ;
return head;
}
2 递归反转链
和迭代反转法相反
实现思想是从链表的尾节点开始
依次向前遍历
遍历过程依次改变各节点的指向,即令其指向前一个节点
link * recursive_reverse(link *head)
{
if(head == NULL ||
head->next == NULL)
{
return head;
}// 递归的出口,空链或只有一个结点,直接返回头指针
else
{
//一直递归 找到链表中最后一个节点
link * new_head = recursive_reverse(head->next);
//当逐层退出时,new_head 的指向都不变,一直指向原链表中最后一个节点;
//递归每退出一层,函数中 head 指针的指向都会发生改变,都指向上一个节点。
//每退出一层,都需要改变 head->next 节点指针域的指向,同时令 head 所指节点的指针域为 NULL。
head->next->next = head;
head->next = NULL;
return new_head;
}
}
3 头插法 反转链表
是指在原有链表基础上,依次将位于链表头部的节点摘下,然后采用从头部插入的方式生成一个新链表,则此链表即为原链表的反转版。
link * head_reverse(link*head)
{
link * new_head = NULL;
link * temp = NULL;
if(head == NULL ||
head->next == NULL )
{
return head;
}
while(head != NULL)
{
temp = head;
//将temp从head中摘除
head = head->next;
//将temp插入到new_head的头部
temp->next = new_head;
new_head = temp;
}
return new_head;
}
4 就地逆置法 反转链表
和头插法的实现思想类似 ,唯一区别在于,头插法是通过建立一个新链表实现的,而就地逆置法则是直接对原链表做修改,从而实现将原链表反转。
在原链表的基础上做修改,需要额外借助2个指针(假设分别为beg end)
link * local_reverse(link * head)
{
link * begin = NULL;
link * end = NULL;
if(head == NULL ||
head->next == NULL )
{
return head;
}
begin = head;
end = head->next;
while(end != NULL )
{
//将 end 从链表中摘除
begin->next = end->next;
//将 end 移动至链表头
end->next = head;
head = end;
//调整 end 的指向,另其指向 beg 后的一个节点,为反转下一个节点做准备
end = begin->next;
}
return head;
}
上述代码仅仅以 无头节点的链表为例
对于有头节点的链表反转:
迭代反转法:
初始状态忽略头节点(直接将 mid 指向首元节点),仅需在最后一步将头节点的 next 改为和 mid 同向即可;
头插法或者就地逆置:
仅需将要插入的节点插入到头节点和首元节点之间即可;
递归法并不适用反转有头结点的链表(但并非不能实现),该方法更适用于反转无头结点的链表。