【面試】Java實現經典八大排序算法及複雜度、穩定性及代碼分析(一)

一、插入排序
1.1 直接插入排序

基本思想

將一個記錄插入到已排好序的序列中,從而得到一個新的有序序列(將序列的第一個數據看成是一個有序的子序列,然後從第二個記錄逐個向該有序的子序列進行有序的插入,直至整個序列有序)

重點:使用哨兵,用於臨時存儲和判斷數組邊界。

        空間複雜度:O(1)。

        時間複雜度:O(n^2)。在最好情況下,表中元素已經有序,此時每插入一個元素,都只需要比較一次而不用移動元素,因此時間複雜度爲O(n^2)。

        穩定性:每次插入元素時總是從後向前先比較再移動,所以不會出現相同元素相對位置發生變化的情況。即直接插入排序是一個穩定的排序方法。

流程圖

算法實現

public class Sort {

    public static void main(String[] args) {

        int arr[] = {2,1,5,3,6,4,9,8,7};

        int temp;

        for (int i=1;i<arr.length;i++){

            //待排元素小於有序序列的最後一個元素時,向前插入
            if (arr[i]<arr[i-1]){
// 假設某時序列 {4,5,6,7} ,下個待插入元素1
                temp = arr[i];
                for (int j=i;j>=0;j--){
                    if (j>0 && arr[j-1]>temp) {
                        arr[j]=arr[j-1];
                    }else {
                        arr[j]=temp;
                        break;
                    }
                }
            }
        }

        System.out.println(Arrays.toString(arr));

    }


}

 

1.2 希爾排序

直接插入排序存在的問題:
當後面插入的數較小的話,前面排好序的元素後移的次數會明顯的增多,對效率有影響。

希爾排序:

在直接插入排序的基礎上進行改進,也稱爲縮小增量排序。

基本思想:

希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序算法排序;隨着增量逐漸減少,每組包含的關鍵詞越來越多,當增量減少至1時,整個元素集合被分成一組,算法便終止。
 

    空間複雜度:O(1)。

   時間複雜度:當n在某個特定範圍時,希爾排序的時間複雜度約爲O(n^1.3)。在最壞情況下希爾排序排序的時間複雜度爲O(n^2)。

   穩定性:當相同關鍵字的記錄被劃分到不同的子表時,可能會改變他們之間的相對次序,因此希爾排序是一個不穩定的排序方法。

動態圖解:

算法實現

import java.util.Scanner;

public class Shell_sort {

//希爾排序是非穩定的排序算法

//基本思想:
//先取一個小於n的整數d1作爲第一個增量,把所有數據分組。所有距離爲d1的倍數的記錄放在同一個分組中。先在各組內進行直接插入排序;
//然後,取第二個增量d2<d1重複上述的分組和排序。直至所取的增量d=1,即所有記錄放在同一組中進行直接插入排序爲止
//一般的初次取序列的一半爲增量,以後每次減半,直到增量爲1

public static void main(String[] args) {
	// TODO Auto-generated method stub
	System.out.println("請輸入數組的大小:");
	Scanner input = new Scanner(System.in);
	int a = input.nextInt();
	int [] arr = new int[a];
	for(int i = 0;i<arr.length;i++) {
		System.out.println("請輸入數組的第"+i+"個值:");
		int s = input.nextInt();
		arr[i] = s;
	}
	arr = HillSort(arr);
	for(int i = 0;i<arr.length;i++)
	System.out.print(" "+arr[i]+" ");
}
public static int[] HillSort(int[] arr) {
	//單獨將數組的長度拿出來,提高效率
	int length = arr.length;
	//截取的長度不爲1則一直計算
	while(length!=0) {
		//取整,相當於每組的元素個數
		length = length/2;
		//每組有多少個元素,就循環幾次
		for(int i =0;i<length;i++) {
			int tem = arr[i];
			//對元素進行分組
			for(int j = i+length;j<arr.length;j+=length) {
				//k的值爲每組最後一個數值的數組下標。
				int k = j-length;
				//將每個要插入進來的數賦給中間變量
				int temp = arr[j];
				//將這個數進行比較,如果小於已排好序的這個數組,那麼數組的位置就往後移
				while(k>=0&&temp<arr[k]) {
					//對應元素後移
					arr[k+length] = arr[k];
					//對應下標前移
					k-= length;
				}
				//找到不小於已排好序的數組中的元素的位置,將其插入
				arr[k+length] = temp;
			}
		}
	}
	return arr;
	
	}
}

 

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