1. 程式人生 > 實用技巧 >[程式設計題] 單鏈錶快排與陣列快排

[程式設計題] 單鏈錶快排與陣列快排

單鏈錶快排與陣列快排

時間:2020.07.23

一、傳統快排思想

思想簡介:

  • 傳統的快速排序演算法使用到遞迴

  • 快排是對氣泡排序演算法的一種改進。基本思想是:通過一趟排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另外一部分的所有資料小,然後再按照此方法對兩部分資料使用遞迴進行如上操作。使得整個資料達到有序序列。

特點:在單項鍊表中無法應用。

圖解

流程

Java程式碼

package demo08;

import java.text.BreakIterator;
import java.util.Arrays;

/**
 * @author jiyongjia
 * @create 2020/7/23 - 10:27
 * @descp:
 */
public class Demo01_kuaipai {
    public static void main(String[] args) {
        int[] arr = new int[]{-9,78,0,23,-2,70,-32,323,-222,421};
        quickSort1(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }


    public static void quickSort(int[] arr,int left,int right){
        int l = left;
        int r = right;
        int mid = (l+r)/2;
        int midValue = arr[mid];

        while (l<r){
            //左找
            while(arr[l]<midValue){
                l++;
            }
            //右找
            while(arr[r]>midValue){
                r--;
            }

            //判斷退出條件
            if(l>=r){
                break;
            }
            //不然的話就交換
            int temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp;

            //處理邊界條件
            if(arr[l] == midValue){
                r--;
            }
            if(arr[r] == midValue){
                l++;
            }
        }

        //處理死鎖
        if(l==r){
            l++;
            r--;
        }

        //左遞迴
        if(left<r){
            quickSort(arr,left,r);
        }
        //右遞迴
        if(right>l){
            quickSort(arr,l,right);
        }

    }

    public static void quickSort1(int[] arr,int left,int right){
        int l = left;
        int r = right;
        int mid = (l+r)/2;
        int midValue = arr[mid];

        while (l<r){
            //左邊找
            while(arr[l]<midValue){
                l++;
            }
            //右邊找
            while (arr[r]>midValue){
                r--;
            }

            //判斷退出條件
            if (l>=r){
                break;
            }
            //找到交換的兩個數字就交換
            int temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp;


            //防止死鎖
            if(arr[l]==midValue){
                r--;
            }
            if(arr[r]==midValue){
                l++;
            }
        }

        if(l==r){
            l++;
            r--;
        }

        //左遞迴
        if(r>left){
            quickSort1(arr,left,r);
        }
        if(l<right){
            quickSort1(arr,l,right);
        }
    }
}

二、快排新思想

思想:

案例

特點:

​ 可以應用在陣列,也可以應用在單向連結串列

實現對陣列的快排

Java程式碼:

package demo08;

import java.util.Arrays;

/**
 * @author jiyongjia
 * @create 2020/7/23 - 16:33
 * @descp: 快排陣列
 */
public class Demo06_quickSort2 {
    public static void main(String[] args) {
        int[] ints = {-2, 3, 5, 3, 88, 8, 1};
        quickSort(ints,0,ints.length-1);
        System.out.println(Arrays.toString(ints));
    }

    public static void quickSort(int[] arr, int left, int right) {
        //遞迴的結束條件
        if(left<right){
            int base = arr[left];  //選擇一個基本的比較的節點,每次預設是該組元素的第一個
            int i = left+1;        // i和j指標都是指向了base後的那個元素
            int j = left+1;

            //j指標一直在後移比較,如果發現小於base的數就和base交換,並且i++;j++;
            //如果j的值不大於base,就j指標一直後移,直到結束
            while (j<=right){
                if(arr[j]<base){
                    swep(arr,i,j);
                    i++;
                }
                j++;
            }
            //當j走到頭的時候,那麼此時就找新的base的位置(老base位置和i指標前的那個數交換)
            swep(arr,left,i-1);
            //左遞迴
            quickSort(arr,left,i-2);
            //右遞迴
            quickSort(arr,i,right);
        }
    }

    //負責交換的函式
    public static void swep(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

}

輸出:

實現對連結串列的快排

Java程式碼:

package demo08;

import com.sun.jndi.toolkit.ctx.StringHeadTail;

/**
 * @author jiyongjia
 * @create 2020/7/23 - 20:37
 * @descp: 快排單鏈表
 */
public class Demo07_quickSortLinkedList {

    //測試用例
    public static void main(String[] args) {
        Node head = new Node(2);
        Node node1 = new Node(1);
        Node node2 = new Node(65);
        Node node3 = new Node(3);
        Node node4 = new Node(8);

        head.next=node1;
        node1.next=node2;
        node2.next=node3;
        node3.next=node4;

        //排序前的連結串列
        System.out.println("排序前的連結串列情況:");
        Node dummy = head;
        while (dummy!=null){
            System.out.print(dummy+"==>>");
            dummy = dummy.next;
        }

        //呼叫
        entrance(head);
    }
    //主要入口方法
    public static void entrance(Node head){
        //如果題目只給了頭節點,我們需要遍歷出尾節點
        Node cur = head;
        while (cur.next!=null){
            cur = cur.next;
        }

        //呼叫連結串列快排
        quickSortLinkedList(head,cur);

        //打印出最終的連結串列情況
        System.out.println("\n排序後的連結串列情況:");
        while (head!=null){
            System.out.print(head+"==>>");
            head = head.next;
        }
    }

    //連結串列快排演算法
    public static void quickSortLinkedList(Node head,Node tail){
        if(head==null || head.next==null || head==tail) {
            return;//結束
        }
        Node base = head;  //基準比較的值,預設是本組的頭節點
        Node i = head.next; //i指標是頭節點後
        Node i_pre = head; //記錄i的前一個節點
        Node j = head.next; //j指標是頭節點後

        while (j!=tail.next){ //j走完了整個連結串列,走到tail
            if(j.val < base.val){
                swep(i,j);  //執行交換i  和 j的值
                i_pre = i; //先記錄i的前一個值
                i = i.next;//再讓i指標後移
            }
            j = j.next;  //j指標後移
        }
        //退出while即走到連結串列尾部,重新找base節
        swep(head,i_pre);
        //左遞迴
        quickSortLinkedList(head,i_pre);
        //右遞迴
        quickSortLinkedList(i,tail);
    }

    //交換兩節點中的值
    private static void swep(Node i,Node j) {
        int temp = i.val;
        i.val = j.val;
        j.val = temp;
    }
}

//節點定義
class Node{
    int val;
    Node next;
    public Node(int val){
        this.val = val;
    }

    @Override
    public String toString() {
        return "Node{" +
                "val=" + val +
                '}';
    }
}

輸出測試結果: