程序员代码面试指南第二版 27.单链表的选择排序

博客介绍了程序员代码面试中关于单链表的选择排序问题。文章详细阐述了选择排序的思想,即从未排序部分找到最小值并放到已排序区域末尾,直到所有元素有序。难点在于指针操作和循环条件,作者分享了左神的解法,通过单独函数获取最小值节点,简化了代码,并强调了维护未排序部分头结点的重要性。
摘要由CSDN通过智能技术生成

welcome to my blog

程序员代码面试指南第二版 27.单链表的选择排序

题目描述
给定一个无序单链表,实现单链表的选择排序(按升序排序)。

输入描述:
第一行一个整数 n,表示单链表的节点数量。
第二行 n 个整数 val 表示单链表的各个节点。

输出描述:
在给出的函数内返回给定链表的头指针。

示例1

输入
5
1 3 2 4 5

输出
1 2 3 4 5
第一次做; 选择排序思想: 从未排序区域找出最小值, 将最小值放到排序区域的最后, 当未排序区域为空时, 元素全部有序; 这道题最麻烦的地方在于指针的操作以及循环条件, 考验代码功底, 要小心不能写错
import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = Integer.parseInt(sc.nextLine());
        //input check
        if(n<1)
            return;
        String[] str = sc.nextLine().split(" ");
        //创建链表
        ListNode head = new ListNode(Integer.parseInt(str[0]));
        ListNode curr = head;
        for(int i=1; i<n; i++){
            curr.next = new ListNode(Integer.parseInt(str[i]));
            curr = curr.next;
        }
        //execute; 链表的选择排序
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode dummy2 = new ListNode(0);
        ListNode p = dummy2;

        ListNode minLeft = dummy, min = head;

        ListNode currLeft = dummy;
        curr = head;
        while(dummy.next!=null){
            while(curr!=null){
                if(curr.val < min.val){
                    minLeft = currLeft;
                    min = curr;
                }
                currLeft = curr;
                curr = curr.next;
            }
            //从原链表中删除值最小的节点
            minLeft.next = min.next;
            //细节; 尾结点会用到, 但不知道哪个是尾结点, 所以就全加上这句即可
            min.next = null;
            //将选出的最小节点放到有序部分的最后
            p.next = min;
            //有序部分扩
            p = p.next;
            //更新minLeft, min
            minLeft = dummy;
            min = dummy.next;
            //更新curr
            curr = dummy.next;
        }
        //打印结果
        curr = dummy2.next;
        while(curr!=null){
            System.out.print(curr.val + " ");
            curr = curr.next;
        }
    }
    public static class ListNode{
        int val;
        ListNode next;
        ListNode(int val){
            this.val = val;
        }
    }
}
左神的解法; 将未排序部分值最小的节点的获取单独写成一个函数, 这样就不用将一堆指针变量写在一块了, 看着整洁些; 没有像我一样创建两个dummy节点; 最需要注意的地方是如何维护未排序部分的头结点: curr = curr == small ? curr.next : curr, 只有curr恰好指向small时才更新
import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = Integer.parseInt(sc.nextLine());
        //input check
        if(n<1)
            return;
        String[] str = sc.nextLine().split(" ");
        //创建链表
        ListNode head = new ListNode(Integer.parseInt(str[0]));
        ListNode curr = head;
        for(int i=1; i<n; i++){
            curr.next = new ListNode(Integer.parseInt(str[i]));
            curr = curr.next;
        }
        //execute; 链表的选择排序
        head = selectionSort(head);
        //打印结果
        curr = head;
        while(curr!=null){
            System.out.print(curr.val + " ");
            curr = curr.next;
        }
    }
    //选择排序
    public static ListNode selectionSort(ListNode head){
        //排序部分的尾结点
        ListNode tail = null;
        //未排序部分的头结点
        ListNode curr = head;
        //未排序部分值最小的节点的前一个节点
        ListNode smallPre = null;
        //未排序部分值最小的节点
        ListNode small = null;
        while(curr != null){
            small = curr;
            smallPre = getSmallestPreNode(curr);
            //值最小的节点前一个节点为空的话, 说明值最小的节点是当前的头结点, 不用执行断链操作
            if(smallPre != null){
                small = smallPre.next;
                smallPre.next = small.next;
            }
            //只有curr是small时才更新curr; 否则保持不变; 这算是个技巧吧
            curr = small == curr ? curr.next : curr;
            if(tail == null)
                head = small;
            else
                tail.next = small;
            tail = small;
        }
        return head;
    }
    //获取未排序区域中值最小的节点的前一个节点
    public static ListNode getSmallestPreNode(ListNode head){
        ListNode smallPre = null;
        ListNode small = head;
        ListNode pre = head;
        ListNode curr = head.next;
        while(curr != null){
            if(curr.val < small.val){
                smallPre = pre;
                small = curr;
            }
            pre = curr;
            curr = curr.next;
        }
        return smallPre;
    }
    public static class ListNode{
        int val;
        ListNode next;
        ListNode(int val){
            this.val = val;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值