插入排序与希尔排序

霸气de小男生 提交于 2019-12-04 07:35:12

插入排序与希尔排序讲解

  希尔排序是打破了O(n^2)时间复杂度的排序方法,它的理念基础是插入排序

插入排序概念

  对同一个数组,我们构思出一个有序数组arr[0],一个无序数组arr[1]开始,无序数组的遍历就是对有序数组的插入元素的筛选

  相比较冒泡和选择的交换式排序方式,插入排序的替换方式更加简单,我们来直接看一下代码演示

插入排序代码 1.0版

/** * 插入排序 * 1.我们可以看做有两个数组,分别是有序和无序的 * 有序:arr[0]开始 * 无序:arr[1]开始 * 我们每次从无序的数据中获取一个,插入到有序列表中,只需要判断当 插入的数据 > 有序中的数据就可以了 * 原因:有序数据本身就是有序的 * */public void insertSorting(int[] arr){    int a;    int value = arr[1]; //记录需要插入的数据    //第一次排序    for(a=0;a>=0;a--){        if(arr[a] < value){            arr[a+1] = value;            break;        }else{            arr[a+1] = arr[a];        }    }    arr[a+1] = value;    //第二次排序    value = arr[2];    for(a=1;a>=0;a--){        if(arr[a] < value){            arr[a+1] = value;            break;        }            arr[a+1] = arr[a];    }    arr[a+1] = value;    //第三次排序    value = arr[3];    for(a=2;a>=0;a--){        if(arr[a] < value){            arr[a+1] = value;            break;        }            arr[a+1] = arr[a];    }    arr[a+1] = value;    //第N次排序    //......}总结:根据排序规律可以看到 无序元素value = 我们需要插入的元素,来自于arr数组索引1后面的所有      有序元素 a = arr[0],当有无序元素进来时判断,及时发现value < arr[0],value需要前移也只是进行arr[a+1] = arr[a]的操作,直到找到了value的位置   我们才进行了交换

插入排序代码 2.0版

/** * 我们通过查看上述规律,提取最大层的for循环控制需要插入的数arr[b] b = 1开始 * */public void insertSorting_2(int[] arr){    int a;    for(int b=1;b<arr.length;b++){        int value = arr[b];        for(a=b-1;a>=0;a--){            if(arr[a] < value){                break;            }                arr[a+1] = arr[a];        }        arr[a+1] = value;    }}

插入排序代码 3.0版

/** *  插入排序继续改进 *  我们继续对以上进行改进 *  a=b-1(代表了我们需要判断的所有索引),a>=0,arr[a] < value 两个判断依据进行提取 * */public void insertSorting_3(final int[] arr){    for(int b=1;b<arr.length;b++){        int value = arr[b];        int a = b-1;        while(a>=0 && arr[a] > value){            arr[a+1] = arr[a];            a--;        }        arr[a+1] = value;    }}

希尔排序概念

  希尔排序的理念基础依旧是插入排序,插入排序如果你吃透了的话看希尔排序会非常的简单,你只需要了解一个思想 --- 步值

希尔排序代码(不完整)和插入排序比较

  我们引入我们之前的插入排序2.0版本的代码来做个比较

/** * 希尔排序 * 有别于插入排序,他进行拆分比较,并通过步长来进行比较 * */public void xrSorting(int[] arr){                int c = 1;    for(int b=c;b<arr.length;b++){        int value = arr[b];        int a;        for(a=b-c;a>=0;a--){            if(arr[a] < value){                break;            }            arr[a+1] = arr[a];        }        arr[a+1] = value;    }}
/** * 插入排序2.0版本,和上述的希尔排序进行对比 * */public void insertSorting_2(int[] arr){    int a;    for(int b=1;b<arr.length;b++){        int value = arr[b];        for(a=b-1;a>=0;a--){            if(arr[a] < value){                break;            }            arr[a+1] = arr[a];        }        arr[a+1] = value;    }}区别:我们对比希尔和插入的代码发现,这个希尔是不是写错了?这不是和插入一样的吗?非也,int c是他们的关键区别,也不能说区别,是插入排序的最终变化   当c = 1的时候看起来和插入完全一致是因为插入的无序arr[1]开始其实就是定义了 c = 1,c可以称之为步长,我们可以让c = 2,3,4,5等等例1:[2, 3, 5, 7, 9, 1, 2, 3, 5, 0],我们让C = arr.length/2 = 5,其实就是拆成了[2,1][3,2][5,3][7,5][9,0]五组分别进行插入输出答案[1, 2, 3, 5, 0, 2, 3, 5, 7, 9]拆成的五组分别为[1,2][2,3][3,5][5,7][0,9]接下来的思路,我们继续 c/2 = 2组,步长C = 2,直至C=1,最后做的一次传统的插入排序
例1:/** * 希尔排序 * 有别于插入排序,他进行拆分比较,并通过步长来进行比较 * */public void xrSorting(int[] arr){                int c = arr.length/2; //这里c = 5    for(int b=c;b<arr.length;b++){        int value = arr[b];        int a;        for(a=b-c;a>=0;a-=5){            if(arr[a] < value){                break;            }            arr[a+5] = arr[a];        }        arr[a+5] = value;    }}

希尔排序代码 1.0版

/** * 希尔排序1.0 * 通过最外层的for循环控制c的变化 * */public void xrSorting(int[] arr){    for(c = arr.length/2;c>=1;c/=2){    for(int b=c;b<arr.length;b++){        int value = arr[b];        int a;        for(a=b-c;a>=0;a-=c){            if(arr[a] < value){                break;                }            arr[a+c] = arr[a];            }        arr[a+c] = value;        }    }}

希尔排序代码 2.0版

/** * 希尔排序2.0 * 和插入排序改进类似,我们提取其中代码进行代码整合 * */public void xrSorting_2(int[] arr){    int c;    for(c = arr.length/2;c>=1;c/=2){        for(int b=c;b<arr.length;b++){            int value = arr[b];            int a = b-c;            while(a >= 0 && arr[a] > value){                arr[a+c] = arr[a];                a-=c;            }            arr[a+c] = value;        }    }}如果我们的c = arr.length / arr.length的话其实本质就是一个原始的插入排序,但是一般情况下我们的时间复杂度要小于O(n^2),对于C的选择要合理
 
 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!