单链表的四种排序算法

285 阅读2分钟

字节面试考到了单链表排序,要求使用快排,自定义单链表数据结构,面试结束之后复盘,使用java写了四种排序算法,分别是插入,归并和快速排序;


/**
 * @author yangshiwei
 * 单链表的四种排序算法
 */
public class ListSortUtils {
    static class ListNode {
        int val;
        ListNode next;

        public ListNode() {
        }

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

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

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("ListNode: ").append(val);
            while (next.next != null) {

                sb.append(" -> ").append(next.val);
                next = next.next;
            }
            return sb.toString();
        }
    }


    public void bubbleSort(ListNode head){
        boolean flag = true;
        ListNode dummy = head;
        while(flag && dummy != null){
            flag = false;
            ListNode pre = dummy;
            while(pre.next != null){
                if(pre.val > pre.next.val){
                    int tmp = pre.val;
                    pre.val = pre.next.val;
                    pre.next.val = tmp;
                    flag = true;
                }
                pre = pre.next;
            }
            dummy = dummy.next;
        }
    }

    /**
     * 插入排序
     * 时间复杂度 O(n ^ 2)
     * 空间复杂度 O(1)
     * @param head ListNode
     * @return ListNode
     */
    public void insertionSortList(ListNode head) {
        if (head == null || head.next == null) return;

        ListNode pre = head;
        ListNode cur = head.next;

        ListNode aux = new ListNode(-1, head); // 辅助结点
        while (cur != null) {
            if (cur.val < pre.val) {
                // 先把cur 节点从当前链表中删除、然后再把cur结点插入到l1和l2之间
                pre.next = cur.next;

                // 从前往后找到 l2.val > cur .val,然后把cur节点插入到l1 和l2之间
                ListNode l1 = aux;
                ListNode l2 = aux.next;
                while (cur.val > l2.val) {
                    l1 = l2;
                    l2 = l2.next;
                }
                l1.next = cur;
                cur.next = l2;
                cur = pre.next; //指向下一个待处理节点
            } else {
                pre = cur;
                cur = cur.next;
            }
        }

    }

    /**
     * 归并排序 自顶向下
     * 时间复杂度 O(NlogN)
     * 空间复杂度 O(logN) 递归调用的栈空间
     * @param head ListNode
     * @return LisNode
     */
    public ListNode mergeSort(ListNode head){
        return mergeSort(head,null);
    }
    public ListNode mergeSort(ListNode head, ListNode tail) {
        if (head == null) {
            return head;
        }
        if (head.next == tail) {
            head.next = null;
            return head;
        }

        // get mid
        ListNode slow = head, fast = head;
        while (fast != tail) {
            slow = slow.next;
            fast = fast.next;
            if (fast != tail) {
                fast = fast.next;
            }
        }

        ListNode mid = slow;
        ListNode list1 = mergeSort(head, mid);
        ListNode list2 = mergeSort(mid, tail);
        ListNode sorted = merge(list1, list2);
        return sorted;
    }

    public ListNode merge(ListNode head1, ListNode head2) {
        ListNode dummyHead = new ListNode(0);
        ListNode temp = dummyHead, temp1 = head1, temp2 = head2;
        while (temp1 != null && temp2 != null) {
            if (temp1.val <= temp2.val) {
                temp.next = temp1;
                temp1 = temp1.next;
            } else {
                temp.next = temp2;
                temp2 = temp2.next;
            }
            temp = temp.next;
        }
        if (temp1 != null) {
            temp.next = temp1;
        } else if (temp2 != null) {
            temp.next = temp2;
        }
        return dummyHead.next;
    }

    /**
     * 快速排序
     * 时间复杂度 O(NlogN) 可能会退化
     * 空间复杂度 O(1)
     * @param head ListNode
     * @param end ListNode
     */
    public void quickSort(ListNode head, ListNode end) {
        if (head != end) {
            ListNode node = portion(head, end);
            quickSort(head, node);
            quickSort(node.next, end);
        }
    }

    private ListNode portion(ListNode head, ListNode end) {
        ListNode p1 = head ,p2 =head.next;
        while(p2 != end){
            if(p2.val < head.val){
                p1 = p1.next;

                int tmp = p2.val;
                p2.val = p1.val;
                p1.val = tmp;
            }
            p2 = p2.next;
        }

        if(p1 != head){
            int tmp = p1.val;
            p1.val = head.val;
            head.val = tmp;
        }
        return p1;
    }

    public void quickSort(ListNode head){
        quickSort(head,null);
    }

}