单链表逆置:
题目:给定一个不带头节点的单链表,要求将他逆序输出
思路一:
定义三个指针tail、p、s。刚开始的时候tail为空,p指向头节点,s指向头节点的下一个节点。
第一次进循环,让p指向tail空,此时头节点p已经断开了他的指向然后将p赋值给tail,此时tail也指向的头节点(控制前面的链表节点)。将s赋值给p,s往后走(控制后面的链表节点)。
第二次循环,让p指向tail(此时的tail是头节点)也就是让p断开了自己的链接并指向了头节点,将p赋值给tail节点(控制前半部分的链表),然后吧s赋值给p,s往后走(控制后半部分的链表)。
…
当s走到空时,此时的p在倒数第一个节点,但是此时的s已经为空,不能再进入循环.,就要停住,否则就会越界。此时退出循环。然后将最后一个节点链接到tail的位置(此时的tail再倒数第二的位置),return p即可
ListNode* reverselist(ListNode* head)//单链表逆置
{
if (head == nullptr || head->next == nullptr) return head;
//如果链表为空,或者只有一个节点,没有逆置的必要,直接return出去
ListNode* Tail = nullptr;//控制前半部分的链表,并等待他后一个节点的链接
ListNode* p = head;//第一个指针,要链接到他的上一个指针,也要找得到他的下一个指针
ListNode* s = head->next;//第二个指针,控制后半部分的链表,也可以作为循环条件
while (s != nullptr)
{
p->next = Tail;//p指向tail,也就是p指向他的前一个节点(头节点有点特殊)
Tail = p;//p指针就是下一次循环要被指向的位置(走到前半部分的最后边)
p = s;//走到后半部分的最前边
s = s->next;//s往后走
}
p->next = Tail;//最后一个节点指向前半部分链表的最后边
return p;//此时p节点就是这个链表的头节点
}
思路二:
我们需要的是让head自己往后移动的同时,还能将单链表逆置。
也就是说,我们需要一个指针s在head的下一个节点的位置,s每次指向head后,往后走一格。
如果要这样做,我们需要将第一个节点的next域指向空。所以我们可以让head先置为空(前提是指针s要指向头节点),然后申请一个临时的节点将s赋值给这个临时的节点。s往后走。让这个节点的next域指向head指针,再将临时节点赋值给head指针。
这里我们不需要担心边界的问题,因为当s等于空时,也就是s走到最后一个节点的next域,也会 申请一个临时的节点来解决。
ListNode* reverselist(ListNode* head)
{
if(head == nullptr || head->next == nullptr) return head;
ListNode* s = head;
ListNode* p = nullptr;//临时的,断桥中间的一根木板
head = nullptr;
//第一个节点逆置后是最后一个节点,而最后一个节点的next域一定是空。
while(s != nullptr)//边界条件
{
p = s;//p得到s的位置
s = s->next;//s往后走
p->next = head;//p的next指向head
head = p;//head也到p的位置,下次指向的时候就可以了
}
//循环退出后head已经到了第一个节点的位置
return head;
}
思路三:
递归:因为是逆序输出,所以应该先让节点走到最后一个位置,然后开始逆置。当s为空时,往回走,定义一个新指针记录最后一个节点(将作为头节点返回),如果返回的节点是第n个,那么返回后的head位置因该是n-1的位置即(n-1)->next=n.那么我们可以让(n-1)->next->next指向第n个节点也就是n节点指向了n-1的节点,这时将n-1的节点的next域指向空,否则到最后我们的末尾节点将指向未知,出错。