(Java版本)快速排序-----數組和鏈表

數組快排

快速排序很多人都懂,大體思路是首先選中一個標誌位(通常選定數組的第一個元素),然後用首尾兩個標識分別找出大於標誌位的和小於標誌位的兩個數,然後交換,接着繼續找下去,直到首尾兩個標識相等,此時再將標誌位於標識交換,就得到了標誌位索麪的元素小於標誌位,右面的大於標誌位,接着遞歸下去就行了。

網上寫代碼的很多,但是感覺都很亂,思路不清晰,這裏我將數組快排的兩種形式(遞歸與非遞歸)寫出來,方便大家快速理解。

    //遞歸方法
    public static void quickSort(int[] array, int low, int high) {
        //遞歸的終止條件就是,如果你的結束標識大於了開始標識就結束
        if (low > high) return;
        int i = low;
        int j = high;
        //選中第一個元素當標誌位
        int key = array[low];
        int t;
        while (i < j) {
            //找到第一個小於key的位置
            while (key <= array[j] && i < j)
                j--;
            //找到第一個大於key的位置
            while (key >= array[i] && i < j)
                i++;
            //交換兩個數
            if (i < j) {
                t = array[i];
                array[i] = array[j];
                array[j] = t;
            }
        }
        //將標誌位和ij的重合位置進行交換
        array[low] = array[i];
        array[i] = key;
        //對標誌位的左面進行快排
        quickSort(array, low, i - 1);
        //對標誌位的右面進行快排
        quickSort(array, i + 1, high);
    }
    //非遞歸
    public static void quickSort(int[] a) {
        Stack<int[]> stack = new Stack<>();
        //棧中存的是每次需要快排的數組的區間的首位標識
        stack.add(new int[]{0, a.length - 1});
        //只要棧不爲空就說明還有若干段沒排好序
        while (!stack.isEmpty()) {
            //彈出第一組排序的首尾標識
            int[] tuple = stack.pop();
            int start = tuple[0], end = tuple[1], i = tuple[0], j = tuple[1];
            //循環和遞歸是一樣的
            while (i < j) {
                while (i < j && a[start] < a[j])
                    j--;
                while (i < j && a[start] >= a[i])
                    i++;
                if (i < j) {
                    int temp = a[j];
                    a[j] = a[i];
                    a[i] = temp;
                }
            }
            if (start != i) {
                int temp = a[start];
                a[start] = a[i];
                a[i] = temp;
            }
            //此時i = j,a[i] = a[j] = key,這個key就是第一個標誌位
            //如果此時,i的左面只有一個start元素,此時就不需要排序了
            if (i - 1 > start)
                stack.add(new int[]{0, i - 1});
            //同理,j的右面只有一個元素end,就不需要排序了
            if (j + 1 < end)
                stack.add(new int[]{j + 1, end});
        }
    }

鏈表快排

整體思想是兩個指針p1和p2,保持p1前面的比key小,p1和p2之間的比key大。key就是我們選取的標誌位,我這裏選的是鏈表的頭結點。

/*class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/

public class l148QuickSortList {
    public static ListNode sortList(ListNode head) {
        quickSort(head, null);
        return head;
    }

    public static void quickSort(ListNode head, ListNode end) {
        if (head != end) {
            //先分再排
            ListNode node = sort(head, end);
            //排序
            quickSort(head, node);
            quickSort(node.next, end);
        }
    }

    public static ListNode sort(ListNode head, ListNode end) {
        //指定兩個指針p1在前,p2在後
        ListNode p1 = head;
        ListNode p2 = head.next;
        while (p2 != null) {
            //如果p2比head的值小的話,p1前進一位,和p2的val進行交換,然後p2再前進一步
            //始終保持p1前面的比key小,p2和p1中間的比key大於等於,p2後面的是沒有比過的
            if (p2.val < head.val) {
                p1 = p1.next;
                int temp = p1.val;
                p1.val = p2.val;
                p2.val = temp;
            }
            p2 = p2.next;
        }
        //如果p1移動了就和key交換值,否則說明都比key大
        if (p1 != head) {
            int tmp = p1.val;
            p1.val = head.val;
            head.val = tmp;
        }
        return p1;
    }
}

看到這裏想必你對快排有了更清晰的認識了,多寫多練!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章