1. 程式人生 > 其它 >演算法基礎二:漸增型演算法---插入排序

演算法基礎二:漸增型演算法---插入排序

演算法基礎二:漸增型演算法---插入排序

一、漸增型演算法是什麼

​ 漸增型演算法(incremental algorithms)指的是演算法使得標識問題的解從較小的部分漸漸擴張,最終成長為完整解。漸增型演算法有一個共同的特徵:構成演算法的主體是一個迴圈結構,它逐步將部分解擴張成一個完整解。該迴圈將遵循一個始終不變的原則:每次重複之初,總維持著問題的一個部分解。我們將此特徵稱為演算法的迴圈不變數(loop invariant)。下面將介紹幾種典型的漸增型演算法。

二、插入排序演算法

1、演算法描述與分析

①問題的理解與描述

輸入:一組數<a1,a2,...,an>

輸出:輸入的一個排列(重排):<a1',a2',...,an'>,滿足a1'<a2'<...<an'

從小到大的順序稱為升序,反之從大到小為降序。

②插入排序的例子

摸撲克牌,我們左手拿著撲克牌,右手去摸牌,每次獲得新的撲克牌後,放入左手,自動為其排序,找到這張撲克牌應在的位置。左手中的撲克牌始終是排好序的,等最後一張摸完之後,也就都排完了序。

③演算法的虛擬碼描述

2、程式實現的注意點

①引數與返回值

引數:一個引數,等待排序的序列A。

返回值:由於排序的結果維持在A中,所以無需返回值。

注意的點:要轉換成程式的時候,需要向程式過程傳遞等待排序的序列A,但是需要考慮A中的 元素是什麼型別,A按怎樣的結構加以儲存(陣列還是連結串列)

②資料設定

INSERTION-SORT中所訪問的變數包括兩重迴圈巢狀的控制變數,i和j,j控制外層的for迴圈,i控制內層while迴圈。初次之外,還需要序列元素A[j]的值暫存變數key。

3、Java語言實現----整型陣列版本

①演算法程式碼

public class InsertSort_01 {

    public static void insertionSort(int[] a){
        int i,j,key,n=a.length;
        for (j=1;j<n;j++){
            key = a[j];//key<-a[j]
            i=j-1;//第一次:key為第二個,i為第一個,兩個作比較。
            while (i>=0 && a[i]>key){//注意此處的大於等於
                a[i+1] = a[i];//前後互換
                i--;//i<-i-1,i一直到不大於key或者為-1,空出來一個位置
            }
            a[i+1] = key;//a[i+1] <- key,填補空缺的那個位置
        }
    }

}

  • 由於a是一個數組,陣列是一個物件,它具有自己的長度屬性length,所有不需要傳遞長度的資訊。
  • 陣列下表從0開始,這點需要注意。
  • 方法被定義為靜態的static,這樣這個方法是從屬於這個類的,而不從屬於該類的任何一個例項物件。因此,可以在需要的時候用“類名.方法名”的形式呼叫。

測試類

public class Test_InsertSort_01 {

    public static void main(String[] args) {
        int A[] = {5,1,9,4,6,2,0,3,8,7};
        int i ;
        InsertSort_01.insertionSort(A);
        for (i = 0; i < 10; i++) {
            System.out.println(A[i]);
        }
        System.out.println();
    }

}

4、Java語言實現---可比較型別陣列版本

①Comparable介面

我們在字串中見到過CompareTo方法,知道這個方法是用於比較字串順序的,根據字典順序進行排序。Java中很多類也都有CompareTo方法,甚至於排序演算法的底層組成也是依賴於比較的,而這個比較就是依賴於各種資料型別的CompareTo或者Compare方法。Java中所有的compareTo方法都源於一個共同的介面,那就是Comparable。這個介面只有一個方法,那就是CompareTo。所有想要具有比較功能的類,都建議實現這個介面,而非是自己定義這個功能,這是面向物件的概念(將具有相同功能的事物抽象到一個共同的類或介面),並且為了多型也建議通過實現介面來進行向上轉型,通過介面來操作具體實現,這也是面向介面程式設計要求我們做的。下面我們來具體瞭解一下Comparable介面。

詳細學習參考:

https://www.cnblogs.com/lin-jing/p/8278271.html
  • 理解:所有實現了Comparable介面的類必須覆蓋此抽象方法,使之能比較這種類的物件x和另一個物件y之間的大小:
x>y返回1,x<y返回-1,x=y返回0
  • 在Java中,只有基本的數值型別(整型、字元型、浮點型)才有比較運算子<、>、<=、>=並且沒有運算子過載功能。

  • int char double float等基本型別的包裝類,Integer Character Double Float等以及字串類String都已經實現了Comparable的類。系統以及為其實現了compareTo方法,可以直接使用。

②演算法程式碼

public class InsertSort_02 {

    public static void insertionSort(Comparable[] a){
        int i,j,n=a.length;
        Comparable key;
        for (j=1;j<n;j++){
            key = a[j];
            i = j-1;
            while (i>=0 && a[i].compareTo(key)>0){//a[i]>key
                a[i+1] = a[i];
                i--;
            }
            a[i+1]=key;
        }
    }

}
  • 引數a由基本整型陣列改變為Comparable型的陣列。這樣,所有實現了Comparable介面的類的物件,就可以作為陣列元素都能用此方法進行排序了。
  • 臨時變數key應當與輸入的陣列元素型別一致,所以它是Comparable型的。
  • a[i].comparaTo(key)>0,可以看出上面我們提到的包裝類比較大小的方式。

③測試程式碼

public class Test_InsertSort_02 {

    public static void main(String[] args) {
        Integer[] a = {5,1,9,4,6,2,0,3,8,7};
        String[] b = {"ChongQing","ShangHai","AoMen","TianJin","BeiJing","XiangGang"};
        Double[] c = {8.5,6.3,1.7,9.2,0.5,2.3,4.1,7.4,5.9,3.7};

        int i;
        InsertSort_02.insertionSort(a);
        for (i=0; i<10; i++){
            System.out.print(a[i]+"");
        }
        System.out.println();

        InsertSort_02.insertionSort(b);
        for (i=0;i<b.length;i++){
            System.out.print(b[i]+"");
        }
        System.out.println();

        InsertSort_02.insertionSort(c);
        for (i=0;i<c.length;i++){
            System.out.print(c[i]+"");
        }
        System.out.println();
    }

}

5、Java語言實現---任意可比較型別線性表容器版本

Java的集合類Collection Framework的標準程式庫中,提供了表示集合的類,包括儲存線性表的List容器。List類有陣列表ArrayList、連結串列LinkedList和向量Vector等子類。利用Java中的類的繼承關係,我們用下面程式解決所有儲存Comparable資料的線性表容器的插入排序問題。

①演算法程式碼

import java.util.List;

public class InsertSort_03 {

    public static void insertionSort(List<Comparable> a){

        int i,j,n=a.size();
        Comparable key;
        for (j=1;j<n;j++){
            key = a.get(j); //key<-a[j]
            i=j-1;
            while (i>=0 && (a.get(i).compareTo(key)>0)){//i>=0且a[i]>key
                a.set(i+1,a.get(i));//a[i+1]<-a[i]
                i--;
            }
            a.set(i+1,key);//a[i+1]<-key
        }

    }

}

程式解析:

  • a的型別是List<Comparable>,說明凡是資料型別實現了Comparable介面的任何繼承List的線性表都可用此函式對其進行插入排序。
  • 元素的下標訪問方式:a.get(i)
  • 改寫值:a.set(i)

②測試程式碼

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;

public class Test_InsertSort_03 {

    public static void main(String[] args) {
        Integer[] a = {5,1,9,4,6,2,0,3,8,7};
        String[] b = {"ChongQing","ShangHai","AoMen","TianJin","BeiJing","XiangGang"};
        Double[] c = {8.5,6.3,1.7,9.2,0.5,2.3,4.1,7.4,5.9,3.7};

        int i;
        ArrayList<Integer> A = new ArrayList<Integer>();
        for (Integer integer : a) {
            A.add(integer);
        }
        Vector<String> B = new Vector<>();
        for (String s : b) {
            B.add(s);
        }
        LinkedList<Double> C = new LinkedList<>();
        for (Double aDouble : c) {
            C.add(aDouble);
        }

        InsertSort_03.insertionSort((List)A);
        System.out.println(A);
        InsertSort_03.insertionSort((List)B);
        System.out.println(B);
        InsertSort_03.insertionSort((List)C);
        System.out.println(C);
    }

}

6、Java語言實現---雙向排序版本

我們可以對線性表進行任何方向的排序。先設計兩個實現了Comparator的類:

import java.util.Comparator;

public class Greater implements Comparator<Comparable> {
    public int compare(Comparable x, Comparable y){
        return x.compareTo(y);
    }
}
import java.util.Comparator;

public class Less implements Comparator<Comparable> {
    @Override
    public int compare(Comparable o1, Comparable o2) {
        return o2.compareTo(o1);
    }
}

解釋說明:

  • 與Comparable介面類似,Comparator介面也只有一個抽象方法compare。與Comparable不同的是,Comparator的compare方法有兩個引數x和y,而Comparable的compareTo方法只有一個引數。
  • Comparable往往依附於某個類,compareTo作為該類的物件的方法完成與另一個同類物件的比較
  • Comparator<T>往往自成一個類,compare方法比較的是類T的兩個物件的大小。
  • 這裡意思就是說,comparator比較的是兩個實現了Comparable類的大小。

①演算法程式碼

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class InsertSort_04 {
    
    public static void insertionSort(List<Comparable> a, Comparator comp){
        int i,j,n=a.size();
        Comparable key;
        for (j=1;j<n;j++){
            key = a.get(j);
            i = j-1;
            while (i>=0 && comp.compare(a.get(i),key)>0){
                i--;
            }
            Collections.rotate(a.subList(i+1,j+1),1);
        }
    }
    
}

②測試類

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;

public class Test_InsertSort_04 {

    public static void main(String[] args) {
        Integer[] a = {5,1,9,4,6,2,0,3,8,7};
        String[] b = {"ChongQing","ShangHai","AoMen","TianJin","BeiJing","XiangGang"};
        Double[] c = {8.5,6.3,1.7,9.2,0.5,2.3,4.1,7.4,5.9,3.7};

        int i;
        ArrayList<Integer> A = new ArrayList<Integer>();
        for (Integer integer : a) {
            A.add(integer);
        }
        Vector<String> B = new Vector<>();
        for (String s : b) {
            B.add(s);
        }
        LinkedList<Double> C = new LinkedList<>();
        for (Double aDouble : c) {
            C.add(aDouble);
        }

        InsertSort_04.insertionSort((List)A,new Greater());
        System.out.println(A);
        InsertSort_04.insertionSort((List)B,new Less());
        System.out.println(B);
        InsertSort_04.insertionSort((List)C,new Less());
        System.out.println(C);
    }

}

三、氣泡排序——練習

1、從小到大排列

public class BubbleSort {

    public static void bubbleSort(int[] a){

        int i,j;

        for (i=0;i<a.length-1;i++){//需要進行length-1次冒泡
            for (j=0;j<a.length-1;j++){
                if (a[j]>a[j+1]){
                    int tmp = a[j];
                    a[j] = a[j+1];
                    a[j+1] = tmp;
                }
            }
        }

    }

}

2、從大到小排列

public static void bubbleSort2(int[] a){

    int i,j;

    for (i=0;i<a.length-1;i++){
        for (j=0;j<a.length-1;j++){
            if (a[j+1]>a[j]){
                int tmp = a[j];
                a[j] = a[j+1];
                a[j+1] = tmp;
            }
        }
    }

}

3、測試

import org.junit.Test;

public class Test_Bubble {

    public static void main(String[] args) {
        int A[] = {5,1,9,4,6,2,0,3,8,7};
        int i ;
        BubbleSort.bubbleSort(A);
        for (i = 0; i < 10; i++) {
            System.out.println(A[i]);
        }
        System.out.println();

    }

    @Test
    public void bubble2(){
        int A[] = {5,1,9,4,6,2,0,3,8,7};
        int i ;
        BubbleSort.bubbleSort2(A);
        for (i = 0; i < 10; i++) {
            System.out.println(A[i]);
        }
        System.out.println();
    }

}