一、 插入排序
依然是在数组的基础上进行排序,插入排序是指把数组拆分为两部门:一部分是已经排好序的,一部分是没有排好序的,从未排序部的第一个元素与已排序比分元素进行比较找到比他小的元素 M,从这个比他小的元素M后面所有元素向后移动一位,此元素插入这个小的元素M后面
初始时所有数据都是未排序状态1-(length-1)的范围,已排好序的数据是(0-0),因为此时只有一个元素。
排序过程:【5,3,2】
1.已排序元素5,未排序元素3,2
2.比较5>3,则3需要插入到5的后面,5向后移动一位【3,5,2】
3.此时3,5是已经排好序的元素,比较5>2,3>2,3已经是第一个元素了,则3后面已经排好序的元素向后移动一位,元素2放入首位,已排序完成结束程序。【2,3,5】
代码:
//插入排序--抓扑克牌
public static void insertionSort(int arr[]){
if(arr == null || arr.length == 0)
return;
for (int i = 1;i<arr.length;i++){
int get = arr[i]; //右手选择待插入数据,未排序数据部分第一个元素
int j = i-1; //以排序好的部分数据的末尾
while(j >= 0 && arr[j] > get){//找出新数据需要插入的位置,原排序好的数据向后移动
arr[j+1]=arr[j];
j--;
}
arr[j+1] = get;//找到需要插入的位置
}
}
由此可以发现每一次插入数据都要与当前已排好数据的前面所以比他大的数据进行比较,如果是一个倒序的数组排序为正序,则会发现越往后比较的次数会越多,能不能减少比较的次数的。答案是能,下面就来介绍这种方式
二、 二分插入排序
1.假设待插入数据A要插入到已排序数据中,此时已排序数据n个,那么则每次与已排好序部分的中间元素进行比较大小,A与(n-1)/2坐标为mid的元素进行比较
2.A =mid 则mid位置开始的元素集体向后移动一位,A插入mid位置
3.A < mid 则从 A-(mid-1)的部分继续需要中间位置进行比较,直至找到最后一个元素区间。
4.A > mid 则从 (mid+1)-(n-1)的部分继续查找中间位置进行比较,直至找到最后一个元素区间。
5.当找到最后一个区间的元素M时,则可以判定A>M前面的所有元素,小于M后面的所有元素。
代码:
//二分插入排序
public static void insertionSortDichotomy(int[] arr){
if(arr == null || arr.length == 0)
return;
for (int i=1;i<arr.length;i++){
int left = 0;//左边界线
int right = i-1;//右边界线
int get = arr[i];//待比较插入数据
while(left<=right){//确定区间数据
int min = (left+right)/2;//区间中间值比较数,选择下一个区间
if(arr[min] < get){ //中间值比待比较值大则左边界右移动
left = min+1;
}else{
right=min-1; //中间值比待比较值小或等于则右边界向左移动
}
}
//假如比较至最后一个元素的区间,区间值比插入值大,则从当前区间位置的数据向后移动
//区间值比插入值小,则从当前区间位置的下一个位置向后移动数据
//left就是插入数据的位置,从它开始向后移动数据的位置,j等于移动坐标结束位置
for (int j = i-1;j>=left;j--){
arr[j+1]=arr[j];//数据移动
}
arr[left]=get;//插入对应位置
}
}
三、二分插入-递归调用
package com.sf;
public class InsertSort {
/**
* 二分插入排序--递归调用
* @param arr 待排序数据
*/
public static void sort(int arr[]){
if(arr == null || arr.length == 0)
throw new IllegalArgumentException("带排序数据为空");
for (int i = 1; i < arr.length; i++) {
int left = 0;//左边界
int right = i-1;//第n次插入,则右边界是n-1,0--(n-1)的坐标已经排序完成
dealSort(arr,left,right,i);
}
}
public static void dealSort(int arr[],int left,int right,int index){
//1.待插入数据
int get = arr[index];
//2.待比较数据范围小于一个元素,则表示已经达到切分极限,需要与此元素进行大小比较确定插入位置
if(left >= right){
if(get < arr[left]){ //< 待插入数据小于比较数据,则从比较数据开始向后移动一步
moveDate(arr,left,index);
}else{
// >= 待插入数据不小于比较数据,则从比较数据后一个元素开始向后移动一步
moveDate(arr,left+1,index);
}
return;//插入数据完成结束本次调用
}
//3.获取中间值,确定下一个范围
int mid = (left+right)/2;
//4.确定下一个数据的范围,进一步缩小
if(arr[mid] == get){//相等于这个中间值,则中间值下一个元素开始移动
//移动数据
dealSort(arr,mid,mid,index);
}else if(arr[mid] > get){ //前半部分
dealSort(arr,left,mid-1,index);
}else{ //后半部分
dealSort(arr,mid+1,right,index);
}
}
/**
* 移动数据,指定位置插入指定数据
* @param arr 数据集
* @param j 从第几个元素开始移动
* @param move 此位置数据插入到指定位置
*/
public static void moveDate(int arr[],int j,int move){
int moveData = arr[move];
for (int i = move; i > j; i--) {
arr[i] = arr[i-1];
}
arr[j] = moveData;
}
public static void main(String[] args) {
// int[] a = {95,5,90};
int[] a = new int[10];
for (int i = 0; i < a.length; i++) {
a[i] = (int) (Math.random() * 100);
}
sort(a);
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+",");
}
}
}