package live.every.day.ProgrammingDesign.CodingInterviewGuide.List;

/**
 * 单链表的选择排序
 *
 * 【题目】
 * 给定一个无序单链表的头节点head,实现单链表的选择排序。
 * 要求:额外空间复杂度为O(1)。
 *
 * 【难度】
 * 简单
 *
 * 【解答】
 * 既然要求额外空间复杂度为O(1),就不能把链表装进数组等容器中排序,排好序之后再重新连接,而是要求面试者在原链表上利用有
 * 限几个变量完成选择排序的过程。选择排序是从未排序的部分中找到最小值,然后放在排好序部分的尾部,逐渐将未排序的部分缩小,
 * 最后全部变成排好序的部分。本文实现的方法模拟了这个过程。
 *
 * 1、开始时默认整个链表都是未排序的部分,对于找到的第一个最小值节点,肯定是整个链表的最小值节点,将其设置为新的头节点记
 * 为newHead。
 * 2、每次在未排序的部分中找到最小值的节点,把这个节点从未排序的链表中删除,删除的过程当然要保证未排序部分的链表在结构上
 * 不至于断开,这就要求我们应该找到要删除节点的前一个节点。
 * 3、把删除的节点(也就是每次的最小值节点)连接到排好序部分的链表尾部。
 * 4、全部过程处理完后,整个链表都已经有序,返回newHead。
 * 和选择排序一样,如果链表的长度为N,时间复杂度为O(N^2),额外空间复杂度为O(1)。
 *
 * 本题依然是考查调整链表的代码技巧,具体过程请参看如下代码中的selectionSort方法。
 *
 * @author Created by LiveEveryDay
 */

public class SelectionSortInList {

    public static class Node {
        public int data;
        public Node next;

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

    public static Node selectionSort(Node head) {
        Node tail = null; // 排好序的链表尾部
        Node cur = head; // 未排序的链表头部
        Node minNodePre; // 最小节点的前驱节点
        Node minNode; // 最小节点
        while (cur != null) {
            minNode = cur;
            minNodePre = getMinNodePre(cur);
            if (minNodePre != null) {
                minNode = minNodePre.next;
                minNodePre.next = minNode.next;
            }
            cur = cur == minNode ? cur.next : cur;
            if (tail == null) {
                head = minNode;
            } else {
                tail.next = minNode;
            }
            tail = minNode;
        }
        return head;
    }

    private static Node getMinNodePre(Node head) {
        Node minNodePre = null;
        Node minNode = head;
        Node pre = head;
        Node cur = head.next;
        while (cur != null) {
            if (cur.data < minNode.data) {
                minNodePre = pre;
                minNode = cur;
            }
            pre = cur;
            cur = cur.next;
        }
        return minNodePre;
    }

    public static void main(String[] args) {
        Node node1 = new Node(7);
        Node node2 = new Node(5);
        Node node3 = new Node(2);
        Node node4 = new Node(3);
        Node node5 = new Node(8);
        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;
        Node n = selectionSort(node1);
        while (n != null) {
            System.out.printf("%d ", n.data);
            n = n.next;
        }
    }

}

// ------ Output ------
/*
2 3 5 7 8
*/