演算法基礎二:漸增型演算法---插入排序
演算法基礎二:漸增型演算法---插入排序
一、漸增型演算法是什麼
漸增型演算法(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();
}
}