8.【入门】单双链表及其反转-堆栈诠释

本文的网课内容学习自B站左程云老师的算法详解课程,旨在对其中的知识进行整理和分享~

网课链接:算法讲解009【入门】单双链表及其反转-堆栈诠释_哔哩哔哩_bilibili

一.值传递和引用传递

分类

  • 基本数据类型:当传递基本数据类型(如int、double、char等)时,传递的是实际值的副本。在方法内部对参数的修改不会影响到原始值。
  • 引用数据类型:当传递引用数据类型(如对象、数组等)时,传递的是对象的引用的副本。虽然在方法内部可以通过引用来修改对象的属性,但无法改变原始引用本身。

代码实现

package listreverse;

public class Transmit {
    public static void main(String[] args) {
        // int、long、byte、short
        // char、float、double、boolean
        // 还有String
        // 都是按值传递
        int a = 10;
        f(a);
        System.out.println(a);

        // 其他类型按引用传递
        // 比如下面的Number是自定义的类
        Number b = new Number(5);//在堆区开辟一个空间存放5,定义一个b指向存放5的地址
        g1(b);//拷贝一个b',也指向5的地址,这行代码的目的是将b'指向null,但b仍然指向5
        System.out.println(b.val);
        g2(b);//同样拷贝一个b',将b'指向空间的值改成6,但b和b'指向的空间是1个,所以b的值也变了
        System.out.println(b.val);

        // 比如下面的一维数组
        int[] c = {1, 2, 3, 4};
        g3(c);
        System.out.println(c[0]);
        g4(c);
        System.out.println(c[0]);
    }

    public static void f(int a) {
        a = 0;
    }

    public static class Number {
        public int val;

        public Number(int v) {
            val = v;
        }
    }

    public static void g1(Number b) {
        b = null;
    }

    public static void g2(Number b) {
        b.val = 6;
    }

    public static void g3(int[] c) {
        c = null;
    }

    public static void g4(int[] c) {
        c[0] = 100;
    }
}

二.单链表反转

题目:反转链表

算法原理

一、总体思路
  • 目的:这个算法的目的是将一个单链表进行反转。例如,原始链表为1 -> 2 -> 3,经过反转后变为3 -> 2 -> 1。
  • 采用的方法:采用迭代的方式,通过不断调整链表节点之间的指针方向来实现反转。
二、具体实现步骤

1.初始化指针

  • 定义了三个指针:pre(初始化为null),head(初始化为链表的头节点)和next(初始化为null)。
  • pre指针用于记录已经反转部分的链表的尾节点(初始时因为还没有反转任何节点,所以为null)。
  • next指针用于临时保存head节点的下一个节点,防止在调整指针时丢失链表后续的节点。

2.迭代过程

  • while (head!= null)循环中:
    • 首先,next = head.next;这一步是保存head节点的下一个节点,因为接下来要改变head节点的next指针指向。
    • 然后,head.next = pre;这是关键的一步,将head节点的next指针指向已经反转部分的链表的尾节点(开始时为null),这样就实现了将当前head节点从原链表中“切断”并连接到反转后的链表上。
    • 接着,pre = head;更新pre指针,将pre指向当前已经处理好(反转)的节点,也就是head节点。
    • 最后,head = next;head指针移动到原链表中的下一个节点,以便进行下一轮的反转操作。

3.返回结果

  • while循环结束后,head指针已经遍历到原链表的末尾(变为null),此时pre指针指向的就是反转后的链表的头节点,所以返回pre

代码实现

// 单链表节点
public static class ListNode {
    public int val;
    public ListNode next;

    public ListNode(int val) {
        this.val = val;
    }

    public ListNode(int val, ListNode next) {
        this.val = val;
        this.next = next;
    }
}

// 反转单链表测试链接 : https://leetcode.cn/problems/reverse-linked-list/
class Solution {

    public static ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode next = null;
        while (head != null) {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }

}

三.双链表反转

题目:给你双链表的头节点 head ,请你反转链表,并返回反转后的链表。

算法原理

一.总体思路
  • 目的是反转一个双链表。双链表与单链表不同,它的每个节点既有指向下一个节点的指针next,也有指向前一个节点的指针last。反转双链表就是要将所有节点的nextlast指针方向都反转过来。
  • 采用迭代的方式,通过逐步调整每个节点的nextlast指针来实现整个双链表的反转。
二.具体实现步骤
  • 初始化指针
    • 定义了两个指针pre(初始化为null)和next(初始化为null),以及双链表的头节点head。这里pre用于记录已经反转部分的双链表的尾节点(初始时因为还没有反转任何节点,所以为null),next用于临时保存head节点的下一个节点,防止在调整指针时丢失双链表后续的节点。
  • 迭代过程
    • while (head!= null)循环中:
      • 首先,next = head.next;这一步是保存head节点的下一个节点,因为接下来要改变head节点的next指针指向。
      • 然后,head.next = pre;这是反转双链表中next指针方向的关键一步,将head节点的next指针指向已经反转部分的双链表的尾节点(开始时为null)。
      • 接着,head.last = next;这一步是调整head节点的last指针,将其指向原双链表中head节点的下一个节点(即之前保存的next节点),这样就保证了双链表的双向性在反转过程中得以维持。
      • 之后,pre = head;更新pre指针,将pre指向当前已经处理好(反转)的节点,也就是head节点。
      • 最后,head = next;head指针移动到原双链表中的下一个节点,以便进行下一轮的反转操作。
  • 返回结果
    • while循环结束后,head指针已经遍历到原双链表的末尾(变为null),此时pre指针指向的就是反转后的双链表的头节点,所以返回pre

代码实现

// 双链表节点
public static class DoubleListNode {
    public int value;
    public DoubleListNode last;
    public DoubleListNode next;

    public DoubleListNode(int v) {
        value = v;
    }
}

// 反转双链表
// 没有找到测试链接
public static DoubleListNode reverseDoubleList(DoubleListNode head) {
    DoubleListNode pre = null;
    DoubleListNode next = null;
    while (head!= null) {
        next = head.next;
        head.next = pre;
        head.last = next;
        pre = head;
        head = next;
    }
    return pre;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值