链表部分翻转-Java

4 篇文章 0 订阅
3 篇文章 0 订阅

题目描述:给定一个链表,翻转该链表从m到n的位置。要求:直接翻转而非申请新的空间;
:给定1–>2–>3–>4–>5,m=2,n=4;m,n满足1<=m<=n<=链表长度;
返回1–>4–>3–>2–>5


算法思路:根据 m 和 n 的值,找到并使 head 指向待翻转链表起始位置的前一个结点,pre 指向起始位置结点保持不变,cur 指向 pre 的 next 结点,每次循环使得 cur 所指结点采用头插法插入到 head 所指结点的后面,cur 和 next 向后指向下一个结点,直到循环结束;

根据 reverse() 函数的传入值,也可以实现翻转链表前半部分或者后半部分;需要获取链表的长度;

流程如下图所示,画的有点粗糙,若是动图能更好的演示这个过程;

这里写图片描述


代码如下所示:

// 链表结点的结构
public class Node {
    public int value;  // 结点值
    public Node next;  // 结点的next

    public Node() {}

    public Node(int value) {
        this.value = value;
    }
}

import java.util.Random;
import java.util.Scanner;

public class ReverseLink {
    public static void main(String[] args) {
        int m, n;  // 输入要改变部分的链表起始位置和结束位置
        int len = 0;
        int mid = 0;  // 若是从中间翻转,需先求出中间结点的位置
        // 生成0~100内的随机数
        Random random = new Random(100);
        // 初始化一个单链表,头结点为空
        Node head = new Node();
        Node pre = head;
        for (int i = 0; i < 20; i++) {
            Node node = new Node(random.nextInt(100));
            pre.next = node;  // 尾插法构建链表
            pre = node;
        }
        System.out.print("原链表:");
        print(head.next);
        len = getLinkedLength(head);
        if(len % 2 == 1) {
            mid = (1 + len) / 2; 
        } else {
            mid = len / 2;
        }
        System.out.println("翻转链表的范围m和n:");
        Scanner sc = new Scanner(System.in);
        m = sc.nextInt();
        n = sc.nextInt();
        System.out.println("m = " + m + " n = " + n);
        // 翻转链表
        reverse(head, m, n);
        // 若是想翻转链表的前半部分或者后半部分,由mid值传入合适参数即可
        // reverse(head, mid+1, len);
        System.out.print("翻转之后的链表:");
        print(head.next);
    }

    /**
     * 打印输出链表的结点值
     */
    public static void print(Node head) {
        while (head != null) {
            System.out.print(head.value + " ");
            head = head.next;
        }
        System.out.println();
    }

    /**
     * 获取链表的长度
     */
    public static int getLinkedLength(Node head) {
        int len = 0;
        while(head.next != null) {
            len++;
            head = head.next;
        }
        return len;
    }

    /**
     * 翻转链表的从结点m到结点n的部分
     * 
     * @param head 连标点额头结点
     * @param m 翻转的开始位置
     * @param n 翻转的结束位置
     * @return 翻转后的新链表
     */
    public static void reverse(Node head, int from, int to) {
        if (from >= to) return;
        Node cur = head.next;
        int i;
        for (i = 0; i < from - 1; i++) {
            head = cur;  
            cur = cur.next;
        }
        Node pre = cur;
        cur = cur.next;
        to--;
        Node next;
        for (; i < to; i++) {
            next = cur.next;
            cur.next = head.next;  // 采用头插法
            head.next = cur;
            pre.next = next;
            cur = next;
        }
    }
}

运行示例:
这里写图片描述


若是翻转链表的前半部分或者后半部分,可以根据mid参数的值,给 reverse() 传入合适的参数,即可实现翻转链表的前半部分或者后半部分;

翻转链表前半部分运行示例:

这里写图片描述


翻转链表后半部分运行示例:

这里写图片描述

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值