1. 程式人生 > >Java演算法——————七大排序

Java演算法——————七大排序

排序演算法的分類:

排序:基本排序:{交換排序:氣泡排序,快速排序。

                             {選擇排序:選擇排序,堆排序

                             {插入排序:直接插入排序,Shell排序

                             {歸併排序

           多路歸併排序:

一:交換排序

1:交換排序的主體操作是對陣列中的資料不斷進行交換操作。

2:交換排序種類:交換排序主要有氣泡排序和快速排序。

1:氣泡排序

(1)氣泡排序流程

——(1)對陣列中的各元素,一次比較相鄰的兩個元素的大小

——(2)如果前面的資料大於後面的資料,就交換著兩個資料。經過第一輪的多次比較排序之後,便可將最小的資料排好

——(3)在用同樣的方法把剩下的資料逐個進行比較,最後便可按照從小到大的順序排好陣列個數據的順序。

(2)冒泡程式碼分析

優點:思路簡單直觀。

缺點:執行的步驟有點長,效率不是很高。

時間效率:時間複雜度為O(n^2),平均O(n^2) ,最壞O(n^2),空間O(1),穩定

空間效率:僅使用了一個輔存單元。

(3)氣泡排序程式碼

public void bubblesort(){
    int[] data={10,9,8,7,6,5,4};
    System.out.println("排序之前");
    System.out.println(java.util.Arrays.toString(data));
    int n=data.length;
    for(int i=0;i<n-1;i++){
       for(int j=0;j<n-1-i;j++){
           if(data[j]-data[j+1]>0){
               int temp=data[j];
               data[j]=data[j+1];
               data[j+1]=temp;
           }
       }
    }
    System.out.println("排序之後:\n");
    System.out.println(java.util.Arrays.toString(data));
}

2:快速排序

(1)快速排序流程

——(1)首先設定一個分界值,通過該分界值將資料分成左右兩個部分。

——(2)將大於等於分界值的資料集中到陣列右邊,小於分界值的資料集中到陣列的左邊。

此時,左邊部分中的各元素都小於等於分界值,而右邊部分中各元素都大於等於分界值。

——(3)然後,左邊和右邊的資料可以獨立排序。對於左側的陣列資料,又可以取一個分界值,將該部分資料分成左右兩部分,

同樣將左邊放置較小值,右邊放置較大值。右邊的資料也做這樣的處理。

——(4)重複上述過程。

(2)快速排序程式碼分析

快速排序,平均O(nlogn),最壞O(n^2),空間O(logn),不穩定

時間效率:待排序序列本身已經有序或逆向有序時,快速排序的時間複雜度為Ο(n 2 ),

而在有序時插入排序的時間複雜度為Ο(n)。

空間效率:

(3)快速排序程式碼

public class AMoNiStack {
    public static void main(String[] args){
        AMoNiStack a=new AMoNiStack();
        int[] b={1,4,5,32,7,54,2};
        a.quicksort(b,0,b.length-1);
        for(int i:b){
            System.out.print(" "+i);
        }
    }
    public void  quicksort(int a[],int start,int end){
        int i=start;
        int j=end;
        boolean flag=true;
        if(i>=j){
            return ;
        }
        while(i!=j){
            if(a[i]>a[j]){
                int temp=a[i];
                a[i]=a[j];
                a[j]=temp;
                flag=!flag;
            }
            if(flag){
                j--;
            }else{
                i++;
            }
        }
        i--;
        j++;
        quicksort(a,start,i);
        quicksort(a,j,end);
    }

}

二:選擇排序

1:簡單選擇排序

(1)選擇排序流程

——(1)首先從原始陣列中選擇最小的1個數據,將其和第一個位置的資料交換。

——(2)接著從剩下的n-1個數據中選擇次小的一個元素,將其和第二個位置的資料對換。

——(3)然後這樣不斷重複,直到最後兩個資料完成對換。至此,便完成了對原始陣列的從小到大的排序。

(2)選擇排序分析:

選擇排序在對n個數據執行的過程中,無論原資料是否有順序,都需要進行n-1步的中間排序。

優點:思路簡單

缺點:執行程式碼優點長,效率不是很高。

效率:時間複雜度O(n^2),空間效率,只需一個輔存空間

簡單選擇排序,平均O(n^2),最壞O(n^2),空間O(1),不穩定

(3)選擇排序程式碼

public class shuzuA {
     static final int SIZE=10;
     public static void main(String[] args){
          int[] shuzu=new int[SIZE];
          int i;
          for(i=0;i<SIZE;i++){
               shuzu[i]=(int)(100+Math.random()*(100+1));
          }
          System.out.println("排序前陣列:");
          for(i=0;i<SIZE;i++){
               System.out.print(shuzu[i]+" ");
          }
          System.out.println();
          selectSort(shuzu);
          System.out.println("排序後陣列:");
          for(i=0;i<SIZE;i++){
               System.out.print(shuzu[i]+" ");
          }
     }
     public static void selectSort(int[] a){
          int index,temp;
          for(int i=0;i<a.length-1;i++){
               index=i;
               for(int j=i+1;j<a.length;j++){//為了找到index這個索引之後的最小值的索引。
                    if(a[j]<a[index]){
                         index=j;//每次比較完,index是最小值的索引。
                    }
               }
               if(index!=i){//交換兩個數
                    temp=a[i];
                    a[i]=a[index];
                    a[index]=temp;
               }
          }
     }
}

2:堆排序(Heap Sort基於選擇排序思想的)

(1)堆排序流程

{什麼是堆結構:堆結構是一種樹結構,是一個完全二叉樹。}

(2)堆排序分析

堆排序,平均O(nlogn),最壞O(nlogn),空間O(1),不穩定

(3)堆排序程式碼

public class DemoJoin{
    static final int SIZE=10;
    static void heapSort(int a[],int n){
        int i,j,h,k;
        int t;
        for(i=n/2-1;i>=0;i--){
            while(2*i+1<n)
            {
                j=2*i+1;
                if((j+1)<n){
                    if(a[j]<a[j+1])
                        j++;
                }
                if(a[i]<a[j])
                {
                    t=a[i];
                    a[i]=a[j];
                    a[j]=t;
                    i=j;
                }
                else
                    break;
            }
        }
        System.out.print("原資料構成的堆:");
        for(h=0;h<n;h++)
            System.out.print(" "+a[h]);
        System.out.println();
        for(i=n-1;i>0;i--){
            t=a[0];
            a[0]=a[i];
            a[i]=t;
            k=0;
            while(2*k+1<i){
                j=2*k+1;
                if((j+1)<i)
                {
                    if(a[j]<a[j+1])
                        j++;
                }
                if(a[k]<a[j])
                {
                    t=a[k];
                    a[k]=a[j];
                    a[j]=t;
                    k=j;
                }
                else
                    break;
            }
        }
    }

    public static void main(String[] args) {
        int[] shuzu=new int[SIZE];
        int i;
        for(i=0;i<SIZE;i++){
            shuzu[i]=(int)(100+Math.random()*(100+1));
        }
        System.out.println("排序前的陣列:");
        for(i=0;i<SIZE;i++){
            System.out.print(shuzu[i]+" ");
        }
        System.out.println();

        heapSort(shuzu,SIZE);

        System.out.println("排序後的陣列:");
        for(i=0;i<SIZE;i++){
            System.out.print(shuzu[i]+" ");
        }
        System.out.println();

    }


}

三:插入排序

1:直接插入排序(Insertion Sort)

(1)直接插入排序流程

——(1)首先對陣列的前兩個資料進行從小到大的排序。

——(2)接著將第3個數據與排好序的兩個資料比較,將第3個數據插入到何時的位置,

——(3)然後,將第四個資料插入到已排好序的前3個數據中。

——(4)不斷重複上述過程,直到把最後一個數據插入到合適的位置。最後,便完成了對原始資料從小到大的排序。

(打撲克,邊抓牌,邊捋牌)

(2)直接插入排序分析

插入排序演算法在對N個數據進行排序時,無論原陣列有無順序,都需要進行N-1步的排序。

優點:在陣列已有一定順序的情況下,排序效率較好。

缺點:如果資料無規則,則需要移動大量的資料。其排序效率也不是很好。

效率:時間複雜度O(n^2),並且是一個穩定的排序方法。

直接插入排序,平均O(n^2),最壞O(n^2),空間O(1),穩定性

(3)直接插入排序程式碼

public class shuzuA {
     public static void main(String[] args){
          int[] shuzu={1,234,42,344,5,3,9};
          insertionSort(shuzu);
          for(int i=0;i<shuzu.length;i++){
               System.out.print(" "+shuzu[i]);
          }
     }
     public static void insertionSort(int[] a){
          int i;
          int j;//需要插入的位置
          int t;//要插入的資料
          int h;
          for(i=1;i<a.length;i++){
               t=a[i];//要插入的資料是a[i],新抓的牌
               j=i-1;//使需要插入的位置的在需要插入的元素的前一個
               while(j>=0&&t<a[j]){
                    a[j+1]=a[j];
                    j--;
               }
               a[j+1]=t;   //將資料t插入到正確的位置。
          }
     }
}

3:Shell排序(希爾排序/縮小增量排序)

(1)shell排序的流程

——(1)將有n個元素的陣列分為n/2個數字序列,第1個數據和第n/2+1個數據為一對,......

——(2)一次迴圈是每一個序列對排好順序

——(3)然後,在變為n/4個序列,在次排序

——(4)不斷重複上述過程,隨著序列減少最後變為一個,也就完成了整個排序。

(2)shell排序的分析

shell排序的時間複雜度是一個複雜的問題,因為shell排序的時間複雜度與步長序列有關。

(3)shell排序的程式碼

public class shuzuA {
     public static void main(String[] args){
          int[] shuzu={1,4,5,7,3,8,9,2};
          System.out.print("原陣列為");
          for(int h=0;h<shuzu.length;h++){
               System.out.print(" "+shuzu[h]);
          }
          System.out.println();
          shellSort(shuzu);
     }
     public static void shellSort(int[] a){
          int i,j;
          int r,temp;//r為間距
          int x=0;
          for(r=a.length/2;r>=1;r/=2){//將陣列元素分為多個數字序列
               for(i=r;i<a.length;i++){
                    temp=a[i];
                    j=i-r;
                    while(j>=0&&temp<a[j]){
                         a[j+r]=a[j];
                         j-=r;
                    }
                    a[j+r]=temp;
               }
               x++;
               System.out.print("第"+x+"步排序結果");
               for(int h=0;h<a.length;h++){
                    System.out.print(" "+a[h]);
               }
               System.out.println();
          }
     }
}

四:合併排序(MergeSort)

(1)合併排序的流程(通過多次的二路合併完成一遍的合併)

——(1)將N個原始資料看成N個長度為1的有序字表,這時妹子字表中只有一個元素,

將他們一次兩兩合併,得到長度為2的若干有序字表

——(2)經過第1次合併,得到長度為2的有序表序列,在將長度為2的有序表序列進行兩

兩合併。得到長度為4的有序字表

——(3)不斷重複,一直到最後得到長度為N的有序字表,從而完成需過程。

(2)合併排序分析

合併排序,平均O(nlogn),最壞O(nlogn),空間O(n),穩定

(4)合併排序的程式碼

public class DemoJoin{
    static final int SIZE=15;
    static void mergeOne(int a[],int b[],int n,int len)
    {
        int i,j,k,s,e;
        s=0;
        while(s+len<n)
        {
            e=s+2*len-1;
            if(e>=n)
                e=n-1;
            //相鄰有序段合併
            k=s;
            i=s;
            j=s+len;
            while(i<s+len&&j<=e)
            {
                if(a[i]<=a[j])
                    b[k++]=a[i++];
                else
                    b[k++]=a[j++];
            }
            while(i<s+len){
                b[k++]=a[i++];
            }
            while(j<=e)
                b[k++]=a[j++];
            s=e+1;
        }
        if(s<n)
        {
            for(;s<n;s++)
                b[s]=a[s];
        }
    }

    static void mergeSort(int a[],int n){
        int h,count,len,f;
        count=0;
        len=1;
        f=0;
        int[] p=new int[n];
        while(len<n){
            if(f==1)
                mergeOne(p,a,n,len);
            else
                mergeOne(a,p,n,len);
            len=len*2;
            f=1-f;
            count++;
            System.out.printf("第"+count+"步排序結果");
            for(h=0;h<SIZE;h++){
                System.out.printf(" "+a[h]);
            }
            System.out.println();
        }
        if(f==1){
            for(h=0;h<n;h++){
                a[h]=p[h];
            }
        }
    }
    public static void main(String[] args) {
        int[] shuzu=new int[SIZE];
        int i;
        for(i=0;i<SIZE;i++){
            shuzu[i]=(int)(100+Math.random()*(100+1));
        }
        System.out.println("排序前的陣列:");
        for(i=0;i<SIZE;i++){
            System.out.print(shuzu[i]+" ");
        }
        System.out.println();
        mergeSort(shuzu,SIZE);
        System.out.println("排序後的陣列:");
        for(i=0;i<SIZE;i++){
            System.out.print(shuzu[i]+" ");
        }
        System.out.println();
    }


}