插入排序java
插入排序是最簡單的一種排序方式。這裏就不去囉嗦繞口的概念了,經過圖去解釋什麼是插入排序程序員
假設一個數組內有以下5個元素,須要對其按照從小到大的順序進行排列。面試
插入排序就是從未排序序列中,取出元素,在已排序序列中一次比較。插入到相應的位置。算法
在上面的五個數字中數組
咱們假設有一個長度爲一的有序系列爲12。學習
而八、1七、3一、22爲無序序列。大數據
從無序序列中取出一個元素8,與有序序列中的12進行比較。比12小,則將其移動到12前面,反之放在後面spa
結果爲:3d
public static void main(String[] args) { Integer[] arr = {12, 8, 17, 31, 22}; // 第一個元素爲有序,所以從i = 1開始 for (int i = 1; i < arr.length; i++) { // 待插入元素 第一次循環arr[i] 就是8 Integer temp = arr[i]; int j; for (j = i - 1; j >= 0; j--) { // 數組中第二個元素與第一個元素比較,12>8 if (temp < arr[j]) /** * 複製j位元素到j+1 * 循環一次是,結果爲十二、十二、1七、3一、22 */ arr[j + 1] = arr[j]; else break; } /** * j + 1 位爲要插入的最小元素 * 循環一次結果爲八、十二、1七、3一、22 */ arr[j + 1] = temp; } System.out.println(Arrays.toString(arr)); }
二分排序code
在說二分排序以前不得不提到二分查找這個基本的算法。那什麼是二分查找呢?
舉個例子,你們應該都玩過猜數字的遊戲,若是從1~100這裏面猜一個數字。我只須要對你猜的數字回答 「大了」、「小了」。直至猜出結果。
若是漫無目的的去猜,運氣很差可能會猜100次。那怎麼樣才能更少次數的猜出結果呢。
假設咱們的目標數字是 66
對於N個元素的列表,咱們要猜出其中一個數字最多隻須要log 2 N次。若是列表中1024個數字,咱們也只須要猜想10次就能夠出來。2的十次方等於1024.
回到咱們的二分插入,原理基本同樣,從無序列表中取出一個元素,跟前面的有序列表的中間數進行比較,若是小了,再進行折半比較,直至找到合適的位置。
如圖,六、九、十二、1八、20爲有序列表,對15進行二分插入
取出有序列表的中間元素12。12< 15。
十二、1八、20取出中間元素,18。18 > 15
在十二、18中進行比較,12<15<18
public static void main(String[] args) { int i, j, right, left, mid, temp; Integer[] arr = {12, 8, 17, 31, 22, 44, 1, 99, 76}; // 依舊把第一個元素當成有序的,所以從i=1開始 for (i = 1; i < arr.length; i++) { //若是後一個元素比前一個元素大,則continue,開始下一次循環 if (arr[i] > arr[i - 1]) { continue; } temp = arr[i]; //最左邊爲二分插入的起始位置 left = 0; //左右定義有序列表的長度 right = i-1; while (left <= right) { //mid爲中間元素的下標 mid = (left + right) / 2; // 中間元素和要插入的元素進行比較 if (arr[mid] < temp) //若是中間元素小,則起始位置爲mid + 1 left = mid + 1; else //同left right = mid - 1; } // 移動元素到相應的位置 for (j = i - 1; j >= left; j--) { arr[j + 1] = arr[j]; } arr[left] = temp; } System.out.println(Arrays.toString(arr)); }
希爾排序
希爾排序又成爲縮小增量排序。假設有一個長度爲N的數組,他的增量設爲X(X<N),將數組拆分爲多個子序列,在每一個子序列中進行直接插入排序。而後減小增量的值,重複以上操做,直至X=1(即一個子序列中只有一個元素)。這樣理解可能比較混亂,看圖說話吧。
如圖,一個長度爲8的無序數組
增量一般取長度的通常,因此增量爲 8/2 = 4。意味着此時被拆分爲4個子序列。
[18 , 10], [22,1],[3,19],[51,55]
我用四種不一樣的顏色進行標識
而後子序列中的元素進行插入排序,即同一顏色的兩個數進行排序,結果爲
而後縮小增量,此時增量爲4/2 = 2。被分爲兩個子序列
[10,3,18,19] ,[1,5 1,22,55]
再次對子序列進行排序,獲得的結果以下
重複上述操做,再次縮小增量直至爲1,通過增量遞減的過程,其實就是元素排序的過程,當增量爲1時,大部分元素其實已經排好順序了,咱們只須要對其進行微調便可。
代碼實現以下
public static void main(String[] args) { Integer[] arr = {18, 22, 3, 51, 10, 1, 19, 55}; // 初始增量一般爲總長度的一半 int mid = arr.length / 2; int i; while (mid > 0) { for (i = mid; i < arr.length; i++) { // 起始下標 int begin = i - mid; int tmp = arr[i]; // 起始下標元素大 則調整位置, while (begin >= 0 && arr[begin] > arr[i]) { arr[begin + mid] = arr[begin]; begin -= mid; } //而且調換位置 arr[begin + mid] = tmp; } // 每次結束,增量縮小一半。也能夠自定義 mid = mid / 2; System.out.println(Arrays.toString(arr)); } }
總結
插入排序適用於少許數據的排序,其時間複雜度爲O(n^2)。
二分排序則是利用了數組可以快速定位的特色,時間複雜度也是O(n^2),適用於較大數據排序
希爾排序的實質是分組再進行直接插入,開始時增量較大時,插入排序的數量少,因此前期會很快。當增量變小時,數據也基本有序了。因此希爾排序的時間複雜度要比O(n^2)要好不少。
最後 歡迎你們關注個人公衆號 程序員共成長。天天都會分享技術乾貨,包括不限於Java、數據量、Linux、職場感悟,大廠面試等。另外還有各類學習資源