反转链表的四种方法

					***由力扣某道题目引出的悲惨故逝***

此处贴上题目链接
https://leetcode.cn/problems/reverse-linked-list/

力扣206题
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表
(我能怎么办,你要不把我办了吧)

1.双指针写法(迭代法)

从前往后地把链表节点指针的指向反转。

代码思路:

  1. 初始化prev为NULL,表示反转后的链表头节点;

    初始化cur为head,表示当前需要处理的节点;

  2. 进入循环,当cur不为NULL时执行以下操作:

    • 保存cur的下一个节点到temp中,以便后续操作;
    • 将cur的next指针指向prev,实现反转;
    • 将prev更新为cur,表示当前节点已经处理完毕;
    • 将cur更新为temp,继续处理下一个节点;
  3. 循环结束后,prev指向反转后的链表头节点,将其返回作为结果


struct ListNode* reverseList(struct ListNode* head){
    struct ListNode* prev = NULL; // 初始化prev为NULL
    struct ListNode* cur = head;  // 初始化cur为head

	while (cur) {
   	 	struct ListNode* temp = cur->next; 
    	// 保存cur的下一个节点到temp中
    	cur->next = prev;                
    	// 将cur的next指针指向prev,实现反转
    	prev = cur;                     
    	// 将prev更新为cur
    	cur = temp;                     
    	// 将cur更新为temp,继续处理下一个节点
	}

return prev; // 返回反转后的链表头节点
}

2.递归法

利用递归 实现链表的反转
递归跳出循环的条件,应该有两个
当 p.next == null表明是最后一个节点,
另一个是P == null,这个时候说明传入时一个空节点,也要返回Null;
两个条件同时满足即可结束递归。

递归思路:
只要让每次进来的节点反转他们的指向,即可完成反转链表
如 传入的节点时 4 -> 5,现在使得5 -> 4

代码思路:

  1. 如果链表为空(head == null)或者只有一个节点(head.next == null),则直接返回头节点,因为这种情况下链表已经是反转的了。
  2. 否则,递归调用reverseList3(head.next),将子链表进行反转,得到反转后的最后一个节点last
  3. 将当前节点head的下一个节点的next指针指向当前节点head,实现当前节点与下一个节点的反转。
  4. 将当前节点headnext指针置为null,避免形成环。
  5. 返回反转后的最后一个节点last
struct ListNode reverseList(ListNode head) {

        if (head == null || head.next == null){
            return head;//返回最后一个节点
        }
       //等所有递结束,开始归的时候调整我们的指针
        ListNode last = reverseList(head.next);
       
        head.next.next = head;
        head.next = null;
        //接收最后一个节点

        return last;
    }

3.就地逆置法

首先需要两个指针

为什么需要两个指针呢?

因为在操作的过程中需要取出中间的一个,这样就会导致后面的数据丢失,当我们有两个指针的时候就可以避免这种情况发生。

注意:在这里我们统一让链表头的不存入数据。

形象的可以把这四步操作总结为“连”,“掉”,“接”,“移”。

连:我们将beg->next=end->next,这样就会避免后面的数据丢失。
掉:接下来将end放在所有数据的前面,就是end->next=head->next。
接:这个时候就要把连移动的数据放在头指针的后面,即head->next=end。
移:最后就是要把下一个需要定义的数据往下移动一位,便是end=beg->next。

代码思路:

首先检查输入的链表是否为空或只有一个节点,如果是,则直接返回头指针。否则,它将使用两个指针(beg和end)来遍历链表并进行反转操作。

在循环中,函数将节点从原位置移除,并将其添加到新的位置。具体步骤如下:

  1. 将beg指针指向当前节点的下一个节点(即原位置的下一个节点)。
  2. 将end指针指向当前节点的下一个节点(即原位置的下下个节点)。
  3. 将beg指针的next指针指向end指针所指向的节点(即将原位置的节点从链表中删除)。
  4. 将end指针的next指针指向head指针(即将节点添加到链表的头部)。
  5. 更新head指针为end指针(即将head指针移动到当前节点的位置)。
  6. 更新end指针为beg指针的next指针(即将end指针移动到原位置的下一个节点)。
  7. 重复以上步骤,直到end指针到达链表的末尾。

最后,函数返回反转后的链表头节点。

struct ListNode* ReverseList(struct ListNode* head ) {
        struct    ListNode*    beg=NULL;
        struct    ListNode*    end=NULL;
        if (head == NULL || head->next == NULL) // 空链或只有一个结点,直接返回头指针
        {
            return head;
        }
        else
        {
        //beg和end指针指向相应的head和head->next
            beg=head;
            end=head->next;
            while(end!=NULL){
        //摘下节点
            beg->next=end->next;
        //将节点添加到表头
            end->next=head;
            head=end;
            end=beg->next;
            }
        }
        return head;
}

4.栈

大概思路:根据栈的后进先出原理,让链表结点先进栈后出栈,就能得到逆序组合。

①在第一个while中,计算栈所需要的空间size。

②在第二个while中,将原链表中的结点地址进栈,注意是结点地址。

③在第三个while中,出栈并按照出栈顺序链接起来,形成新的链表。

代码思路:

首先检查链表是否为空或只有一个节点,如果是,则直接返回原链表头节点。

接下来,函数通过遍历链表来计算链表的长度,并将每个节点存储在一个栈中。然后,从栈顶开始逐个弹出节点,并将其连接起来,形成反转后的链表。

最后,将最后一个节点的next指针设置为NULL,表示反转后的链表结束。

struct ListNode* reverseList(struct ListNode* head){
    if(head==NULL||head->next==NULL){
        return head;
    }
    int size=0;struct ListNode* p=head;
    while(p!=NULL){
        size++;
        p=p->next;
    }
    struct ListNode*stack[size];
    int top=-1;p=head;
    while(p!=NULL){
        stack[++top]=p;
        p=p->next;
    }
    struct ListNode* head2=stack[top];
    p=head2;
    while(top!=-1){
        p->next=stack[top--];
        p=p->next;
    }
    p->next=NULL;
    return head2;
}
  • 32
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值