206.反转链表(Java/C)三种解法

206.反转链表

1.方法一:通过头插法遍历链表,再插入新链表中

image-20230914203340001

Java代码实现:

public ListNode reverseList(ListNode head) {
        if (head == null) return null;
        //1.创建新链表,用来存放反转链表
        ListNode reverse = null;
        //2.遍历链表元素,将链表中的元素添加到数组
        for (ListNode p = head; p != null; p = p.next) {
            //3.头插入代码
            reverse = new ListNode(p.val, reverse);
        }
        return reverse;
    }

C代码实现:

struct ListNode* reverseList(struct ListNode* head){
    //1.如果链表为空,返回空链表
	if(head == NULL) return NULL; 
	//2.创建新链表,将反转的链表装此链表中
	struct ListNode *newList = NULL;
	//3.遍历链表,实现链表反转
	for (struct ListNode *p = head; p != NULL; p = p->next){
		//4.头插法实现链表反转
		struct ListNode *node = (struct ListNode*) malloc(sizeof(struct ListNode));
		node->val = p->val;
		node->next = newList;
        newList = node;
	} 
	return newList;
}
2.方法二:递归遍历
  • 递归算法的一般步骤
  1. 定义基本情况:确定一个或多个基本情况,即无需再次递归求解的情况。这是递归的终止条件。
  2. 缩小问题规模:将原始问题转化为一个或多个规模较小的子问题。通常,这一步可以通过参数的改变、数组的切割等方式实现。
  3. 调用自身:在解决子问题时,调用自身来求解更小规模的同种问题。这就是递归的核心思想。
  4. 组合结果:将子问题的解组合起来,得到原始问题的解。

在实现递归算法时,需要注意确保基本情况能够被满足,并且每次递归都能使问题规模减小。同时,递归算法要注意避免出现无限递归的情况,因此通常需要设置递归深度限制或者其他终止条件。

Java代码实现:

    public ListNode reverseList2(ListNode p){
        //递归结束的条件:
        //1.如果链表为空  2.遍历后的下一个节点为空,即链表已经遍历完成
        if (p == null || p.next == null){
            return p;//最后节点
        }
        //2.进行递归遍历
        ListNode last = reverseList2(p.next);
        //3.遍历结果进行处理
        p.next.next = p;
        p.next = null;
        return last;
    }
  • 以反转链表[1,2,3,4,5]进行递归举例

image-20230914222344622

上图来自黑马的2023新版数据结构与算法Java视频教程(上篇)!!!

last变量的解释:

在这段代码中,last 是一个临时变量,用于存储递归调用返回的反转后的子链表的头节点。具体来说,last 代表的是递归调用 reverseList2(p.next) 的返回值,即以当前节点的下一个节点为头节点的子链表的反转结果。我们将 last 的作用是为了保留这个反转后的子链表的头节点,以便将其与当前节点 p 进行连接。在递归的最外层调用中,当递归结束后,last 将存储的是整个链表反转后的头节点。在递归的每一层调用中,last 存储的是当前层递归调用返回的子链表反转后的头节点。通过这种方式,我们可以在每一次递归调用时保存子链表反转后的头节点,并将其与当前节点进行连接操作。因此,last 的作用是临时存储递归调用返回的子链表反转的结果,以便正确地进行链表节点的连接。

C代码实现:

//方法二:递归遍历
Node* reverseList2(Node *p){
	//1.递归终止条件
	if(p == NULL || p->next == NULL) return p; 
	
	//2.进行递归遍历
	Node *last = reverseList2(p->next);
	
	//3.对遍历结果进行操作
	p->next->next = p;
	p->next = NULL;
	return last; 
}
3.方法三:双指针法

image-20230915114514457

image-20230915120945630

Java代码实现

public ListNode reverseList3(ListNode oldNode){
        //ListNode oldNode:代表旧链表的头指针
        //ListNode newNode:代表新链表的头指针
        //ListNode oldNode2:代表旧链表的头指针的下一个节点
        //1.当链表为空,或者链表只有一个元素时,不需要进行反转
        if (oldNode == null || oldNode.next == null) return oldNode;
        //2.定义节点
        ListNode oldNode2 = oldNode.next;
        ListNode newNode = oldNode;
        //3.反转操作
        while (oldNode2 != null){
            oldNode.next = oldNode2.next;//将要反转的节点与链表断开
            oldNode2.next = newNode;//将反转的节点接到头部
            newNode = oldNode2;//重新将新节点指针放在链表头部
            oldNode2 = oldNode.next;
        }
        return newNode;
    }

C代码实现

struct ListNode* reverseList3(struct ListNode* oldNode){
    // ListNode* oldNode: 代表旧链表的头指针
    // ListNode* newNode: 代表新链表的头指针
    // ListNode* oldNode2: 代表旧链表的头指针的下一个节点

    // 1. 当链表为空,或者链表只有一个元素时,不需要进行反转
    if (oldNode == NULL || oldNode->next == NULL) return oldNode;

    // 2. 定义节点
    struct ListNode* oldNode2 = oldNode->next;
    struct ListNode* newNode = oldNode;

    // 3. 反转操作
    while (oldNode2 != NULL){
        oldNode->next = oldNode2->next; // 将要反转的节点与链表断开
        oldNode2->next = newNode; // 将反转的节点接到头部
        newNode = oldNode2; // 重新将新节点指针放在链表头部
        oldNode2 = oldNode->next;
    }

    return newNode;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值