前言
折半插入排序演算法是一種排序的演算法,它通過“折半尋找”在比較區尋找插入點的位置,這樣可以減少比較的次數,移動的次數不變,時間複雜度仍為
O(n^2); 演算法描述 將第一個元素當做一個尋找區的元素,剛開始這個尋找區僅含ary[0](第一個元素) 取出下一個元素(這裡迴圈擷取,從第二個元素開始),和尋找區的中間元素(半查法)比較。註:尋找區裡面的元素都排好序了 如果新的元素小於中間元素,將尋找區的右邊界(right變數表示)向左移動一位,如果大於等於中間元素,將左邊界(left變數表示)左移一位 重複步驟3,直到左邊界大於右邊界 判斷左邊界是否在尋找區裡面,如果是就從找到的索引位置開始,到該比較元素索引位置結束,向後移動一位。如果在右邊界外面,則忽略這一步 將找到的位置元素用比較的元素(第二步取出的資料)覆蓋 重複第二步
提示:上面從第二步開始到第7步結束,每一次迴圈比較區裡面的右邊界都在遞增,直到遞增結束 演算法描述圖
以上是在開始寫這篇文章的基礎知識,如果還是看不懂沒關係,我找到一個講解比較好的連結,請看下面的參考資料 為什麼寫這篇文章
這篇文章與其說是來記錄折半排序演算法,還不如說是一次總結,從後面我貼出的代碼可以看出我特意在封裝類中應用了泛型、內部類、以及提供2個Comparable與Comparator的實作類別調用的重載的排序方法,算是對自己前面階段鞏固java基礎一次檢驗,我也希望能對看到這篇文章的人有所協助,由於自身水平的關係,如有錯誤的地方,希望能指出。 本文
在前言中我描述了折半排序演算法的步驟以及原理,我下面從一個實現該演算法的代碼入手來分析一下
public void binarySort(T[] obj , Comparator<T> comparator ) { //定義折半插入演算法所需的一些變數 int left, right, mid; T curValue = null; for( int start = 1; start < obj. length; start++) { curValue = obj[ start]; left = 0; right = start - 1; //下面代碼在比較區使用半查法找出可以插入的位置 while( left <= right) { //使用位元運算找出比較區中間位置 mid = ( left + right) >> 1; if( comparator.compare( curValue, obj[ mid]) < 0) { //當curValue小於obj[mid],右邊界左移 right -= 1; } else { //這裡需要注意一下,如果兩個值相等也讓左邊界向左移動一位 left += 1; } } //結束迴圈以後left = right + 1; 且 left <= start //left就是需要插入元素的位置,moveStep表示將left - start之間的元素後移一位 int moveStep = start - left; System. arraycopy(obj, left, obj, left+1, moveStep); obj[ left] = curValue; } }
從上面我們可以看到代碼有兩個迴圈,第一個for迴圈是對應2-7步驟,第二個while迴圈對應2-4步驟,我們需要注意一下,start是從數組第二個元素開始的,第一個元素我設定成尋找區間元素,右邊界right和這個start有關,這樣才能讓尋找區間不斷的擴充。等while迴圈結束以後,表示我已經找到插入的位置了,接下去通過arraycopy函數,將合格數組向右移動以後,然後用待比較資料去覆蓋找到的索引上的值
我覺得有必要提醒一下就是半查法是針對已經排好序的數組,所以尋找區間按照設定,不斷擴張的以後,裡面的資料也是排序好的
測試代碼
package org.study.arithmetic;import java.util.Arrays;import java.util.Comparator;import java.util.Random;public class BinarySortAc<T> { /** * 折半插入演算法排序 * @param 外面傳遞一個需要排序的數組引用 */ public void binarySort(T[] obj, Comparator<T> comparator) { //定義折半插入演算法所需的一些變數 int left, right, mid; T curValue = null; for( int start = 1; start < obj. length; start++) { curValue = obj[ start]; left = 0; right = start - 1; //下面代碼在比較區使用半查法找出可以插入的位置 while( left <= right) { //使用位元運算找出比較區中間位置 mid = ( left + right) >> 1; if( comparator.compare( curValue, obj[ mid]) < 0) { //當curValue小於ojb[mid],右邊界左移 right -= 1; } else { //這裡需要注意一下,如果兩個值相等也讓左邊界向左移動一位 left += 1; } } //結束迴圈以後left = right + 1; 且 left <= start //left就是需要插入元素的位置,moveStep表示將left - start之間的元素後移一位 int moveStep = start - left; System. arraycopy(obj, left, obj, left+1, moveStep); obj[ left] = curValue; } } @SuppressWarnings({ "unchecked", "rawtypes" }) /** * 排序重載的方法,這裡我無法在使用泛型了,因為泛型由於無法調用compareTo方法 * @param obj 需要比較的資料集合 */ public void binarySort(Object[] obj) { //定義折半插入演算法所需的一些變數 int left, right, mid; Comparable curValue = null; for( int start = 1; start < obj. length; start++) { curValue = (Comparable) obj[ start]; left = 0; right = start - 1; while( left <= right) { mid = ( left + right) >> 1; if( curValue.compareTo( obj[ mid]) < 0) { right -= 1; } else { left += 1; } } //結束迴圈以後left = right + 1; 且 left <= start //left就是需要插入元素的位置,moveStep表示將left - start之間的元素後移一位 int moveStep = start - left; System. arraycopy(obj, left, obj, left+1, moveStep); obj[ left] = curValue; } } @SuppressWarnings("unchecked") /** * @return 返回一個具體的集合 */ public User<String>[] getList() { User<String>[] users = new User[10]; for( int index = 0; index < 10; index++) { User<String> user = new User<String>(); user.setName( "Abigail"+ index); user.setAge( new Random().nextInt(100)); users[ index] = user; } return users; } /** * * * @param <T> User使用外圍類的泛型參數 */ private static class User<V> { private V name; private int age; public V getName() { return name; } public void setName(V name) { this. name = name; } public int getAge() { return age; } public void setAge( int age) { this. age = age; } public String toString() { StringBuilder sbu = new StringBuilder(); return sbu.append( "[name:") .append( name) .append( ",age:") .append( age) .append( "]").toString(); } } /** * @return 返回一個具體的比較子 */ public Comparator<User<String>> getComparator() { return new MyComparator(); } /** * 內部類實現一個User的比較子 * @param args */ private class MyComparator implements Comparator<User<String>>{ @Override /** * 用年齡來比較兩個對象的大小 */ public int compare(User<String> o1, User<String> o2) { return o1.getAge() - o2.getAge(); } } public static void main(String[] args) { BinarySortAc<Integer> ite = new BinarySortAc<Integer>(); Integer[] ites = new Integer[] {5,2,10,6,4,3,1,5,10}; System. out.format( "排序前%s\n", Arrays.toString(ites)); ite.binarySort( ites); System. out.format( "排序後%s\n", Arrays.toString(ites)); BinarySortAc<User<String>> ite1 = new BinarySortAc<User<String>>(); User<String>[] users = ite1.getList(); System. out.format( "排序前%s\n", Arrays.toString(users)); ite1.binarySort( users, ite.getComparator()); System. out.format( "排序後%s\n", Arrays.toString(users)); }}
參考資料
折半插入排序演算法描述(左小右大)
http://wenku.baidu.com/link?url=16JgfPzd4KYlB8rMYULIINnnWSvTcAy916vgxlQpCE47H3D8x96k2wJx0CNaJ8urQyAQ70pKnHYVHeAxoeyK34tsKaasUgKkf5zSVgIZUJe