二分法排序
算法思想简单描述:
在插入第i个元素时,对前面的0~i-1元素进行折半,先跟他们 中间的那个元素比,
如果小,则对前半再进行折半,否则对后半 进行折半,直到left>right,
然后再把第i个元素前1位与目标位置之间 的所有元素后移,再把第i个元素放在目标位置上。
二分法排序最重要的一个步骤就是查找要插入元素的位置,
也就是要在哪一个位置上放我们要准备排序的这个元素。
当我们查找到位置以后就很好说了,和插入排序一样,
将这个位置以后的所有元素都向后移动一位。这样就实现了二分法排序。
然后是怎么查找着一个位置呢,就是不断的比较已排序的序列中的中间元素和要排序元素,
如果中间元素大于要排序元素的话,说明这个要排序的元素在已排序序列中点之前的序列。
public static void DichotomySort(int[] array) { for (int i = 0; i < array.Length; i++) { int start, end, mid; start = 0; end = i - 1; mid = 0; int temp = array[i]; while (start <= end) { mid = (start + end) / 2; if (array[mid] > temp) //要排序元素在已经排过序的数组前半部分 { end = mid - 1; } else // 要排序元素在已经排序的数组后半部分 { start = mid + 1; } }
for (int j = i - 1; j > end; j--) //找到了要插入的位置,然后将这个位置以后的所有元素向后移动 { array[j + 1] = array[j]; } array[end + 1] = temp; } }
二分插入排序实际上是对插入排序的优化。
(1)算法思想
根据插入排序的思想,在插入待排序列的第i个元素时,由于前面的序列已经有序,因此可以使用二分法寻找第i个元素的正确位置。
(2)伪代码:
BinInsertSort( int a[ ], int n ) { int key, left, right, middle; for ( int i = 1; i < n; i++ ) { key = a[ i ]; left = 0; right = i - 1; while ( left <= right ) { middle = ( left + right ) / 2; if ( a[ middle ] > key ) right = middle - 1; else left = middle + 1; } for ( int j = i - 1; j >= left; j-- ) { a[ j + 1 ] = a[ j ]; } a[ left ] = key; } }
折半插入排序其实就是直接插入排序的一种改进,引入了二分查找算法,这样关键字的比较次数就会减少,
数量级为O(nlog^2n),但是元素移动次数还是O(n^2),所以折半插入排序的时间复杂度是O(n^2)。
另外,折半插入排序是稳定的排序算法;下面是用JAVA写的算法的两种实现方式。不过原理都是一样的
import java.util.Arrays; public class BinarySearch1 { public static void main(String args[]) { int array[]= { 49,38,65,97,76,13,27}; binarySort(array,array.length); System.out.println("---------排序后的结果----------"); System.out.println(Arrays.toString(array)); } //二分查找 public static int binarySearch(int array[],int low,int high,int temp) { int mid=0; while(low<=high) { mid=(low+high)/2; if(array[mid]<temp&&temp<=array[mid+1]) return (mid+1); else if(array[mid]<temp) low = mid + 1; else high = mid -1; } return high; } //二分排序 public static void binarySort(int array[],int size) { int i,j,k,temp; for(i=1;i<size;i++) { temp=array[i]; if(array[i]<array[0]) k=0; else k = binarySearch(array,0,i,temp); for(j=i;j>k;j--) { array[j]=array[j-1]; } array[k]=temp; System.out.println(Arrays.toString(array)); } } }
[38, 49, 65, 97, 76, 13, 27] [38, 49, 65, 97, 76, 13, 27] [38, 49, 65, 76, 97, 13, 27] [13, 38, 49, 65, 76, 97, 27] [13, 27, 38, 49, 65, 76, 97] ---------排序后的结果---------- [13, 27, 38, 49, 65, 76, 97]
package sort; import java.util.Arrays; public class BinarySearch2 { public static void main(String args[]) { int array[]= { 49,38,65,97,76,13,27}; binaryInsertSort(array,array.length); System.out.println("------------排序后的结果-------------"); System.out.println(Arrays.toString(array)); } /** * * @param array 要排序的数组 * @param size 数组的大小 */ public static void binaryInsertSort(int []array,int size) { int i,j,temp; int low,high,mid; for(i=1;i<size;i++) { //将待插入的元素赋给temp,这个元素前面是有序数组,用于插入到有序数组中 temp=array[i]; low=0; high=i-1; while(low<=high) { //有序数组的中间坐标,此时用于二分查找,减少查找次数 mid = (low+high)/2; //如果有序序列中的中间元素大于待排序的元素,则有序序列的中间坐标向前搜索,否则向后搜索 if(array[mid]>array[i]) high=mid-1; else low = mid + 1; } /** * j首先赋值为要插入值的前一个元素的最后的坐标,也就是有序数组中最后一个元素的坐标 * 然后依次向前扫描有序数组,然后如果满足条件则向后移动数据 */ for(j=i-1;j>=low;j--) { array[j+1]=array[j]; } //将待排序的元素插入到array数组中 array[low]=temp; System.out.println(Arrays.toString(array)); } } }
[38, 49, 65, 97, 76, 13, 27] [38, 49, 65, 97, 76, 13, 27] [38, 49, 65, 97, 76, 13, 27] [38, 49, 65, 76, 97, 13, 27] [13, 38, 49, 65, 76, 97, 27] [13, 27, 38, 49, 65, 76, 97] ------------排序后的结果------------- [13, 27, 38, 49, 65, 76, 97]