插入排序算法
来源:互联网 发布:信息比率 知乎 编辑:程序博客网 时间:2024/06/08 04:35
插入排序有:直接插入排序、二分法插入排序、希尔排序。
排序是一种很直观的算法,用一种可视化的方法来观察算法的执行过程是很有用的,各位可以点击此链接https://visualgo.net/en/sorting来更加透彻得领悟各类排序算法。
下面是直接插入排序:
基本思想就是,p从1开始一直往后移动,每次移动(即指外层循环的每次循环)前从索引0到p-1位置都是已经排好序的,每次移动后保证从索引0到p位置都是已经排序了的,看起来好像在内层循环要不停的交换元素,实际上不需要,只需要先把元素存起来,元素一直往后复制以覆盖,最后循环结束后再赋值。这和堆的插入删除算法(即上滤下滤)是类似的。
因为有两个循环,所以算法的时间复杂度:
最坏情况:是O(n2)。
最好情况:是O(n)。最好的情况就是数据已经预先排过序了。
算法是稳定的。
public static <AnyType extends Comparable<? super AnyType>> void insertionSort( AnyType [ ] a ) { int j; for( int p = 1; p < a.length; p++ ) { AnyType tmp = a[ p ];//先将要插入的元素存起来 for( j = p; j > 0 && tmp.compareTo( a[ j - 1 ] ) < 0; j-- )//如果是<=0那么算法不稳定 a[ j ] = a[ j - 1 ];//比较后如果小,那么元素就往后移动 if(j!=p) //如果j=p,那么说明p元素就应该在p位置,不需要多余的赋值操作 a[ j ] = tmp;//出了循环,代表j已经到了该到的位置,把tmp赋值给j位置 } }
下面是二分插入排序:
基本思想就是,p从1开始一直往后移动,每次移动(即指外层循环的每次循环)前从索引0到p-1位置都是已经排好序的,每次移动后保证从索引0到p位置都是已经排序了的。但是在寻找插入位置有点不一样了,是通过二分查找的思想来找。二分插入排序的主要操作为比较+后移赋值。
最坏情况:每次都在有序序列的起始位置插入,则整个有序序列的元素需要后移,时间复杂度为O(n2)。
最好情况:待排序数组本身就是正序的,每个元素所在位置即为它的插入位置,此时时间复杂度仅为比较时的时间复杂度,为O(log2n)。
平均情况:O(n2)。
算法是稳定的。
public static void sort(int[] a) { for (int i = 1; i < a.length; i++)//从一开始即可,因为只有一个元素便不用比较 { int temp = a[i];//前把i元素存起来 int left = 0;//都是从0到i-1的位置中找到i元素的插入位置 int right = i - 1; int mid; while (left <= right) { mid = (left + right) / 2; if (temp < a[mid]) { right = mid - 1; } else { left = mid + 1; } }//退出whihe循环时,left肯定等于right+1,,而这个位置就是插入位置 for (int j = i - 1; j >= left; j--) a[j + 1] = a[j];//元素往后移动 if(left!=i)//当i元素就应该放在i位置时,此时left就会等于i位置,但此时不需要进行插入 a[left] = temp; } }
下面是希尔排序:
基本思想是:先取一个小于数组长度的整数d1作为第一个增量,把文件的全部记录分组,一共分为d1组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量
希尔排序的时间复杂度与增量序列的选取有关:
如果是选取的希尔增量:
最坏情况:是O(n2)。
最好情况:是O(n)。
平均情况:
算法是不稳定的。
其余的增量序列还有Hibbard:{1, 3, 7 ..., 2^k-1},Sedgewick:{1, 5, 19, 41, 109...}该序列中的项或者是9*4^i - 9*2^i + 1或者是4^i - 3*2^i + 1。
public static <AnyType extends Comparable<? super AnyType>> void shellsort( AnyType [ ] a ) { int j; for( int gap = a.length / 2; gap > 0; gap /= 2 )//增量gap最开始为长度一半,一直到gap为1 //进入最外层循环后就可以把gap当成常数 //以下两个循环其实就是插入排序 //把数组分成gap个子数组,每个子数组的插入排序,是依次一部分一部分进行的 for( int i = gap; i < a.length; i++ )//不用i=0开始,因为只有一个元素的时候不用排序 { AnyType tmp = a[ i ];//将要插入的元素存起来 for( j = i; j >= gap && tmp.compareTo( a[ j - gap ] ) < 0; j -= gap ) //判断条件也可以写成j>0,一样效果,保证gap个数前的那个元素不是null a[ j ] = a[ j - gap ];//元素后移 if(j!=i)//如果j=i,那么说明i位置的元素就应该在i位置,不需要多余的赋值操作 a[ j ] = tmp; } }
- 排序算法-插入排序
- 排序算法--插入排序
- 排序算法---插入排序
- 排序算法-插入排序
- 排序算法-插入排序
- 排序算法--插入排序
- 排序算法-插入排序
- 排序算法-插入排序
- 排序算法---插入排序
- 排序算法--插入排序
- 排序算法--插入排序
- 排序算法--插入排序
- 排序算法-插入排序
- 排序算法--插入排序
- 排序算法-插入排序
- 排序算法-插入排序
- 排序算法--插入排序
- 排序算法-插入排序
- tensorflow编程: Neural Network
- springmvc-Controller类的方法的不同返回值类型
- angularJS自定义服务的两种方法
- [bzoj2002][LCT]弹飞绵羊
- mvc中使用Unity
- 插入排序算法
- spring boot thymeleaf错误之Circular view path [...]
- Java里数字转字符串前面自动补0的实现
- 【BZOJ1008】【HNOI2008】越狱(组合数学)
- Android 内存泄漏和优化(上)
- C语言动态内存开辟malloc, realloc ,calloc,free详解
- mahout学习之聚类(1)——向量的引入与距离测度
- C#.net将Word转PDF
- 修改maven私服上的公共pom配置