前言
本章讨论排序中插入排序的相关内容
方法
1.概念
插入排序(Insertion sort)是一种简单直观且稳定的排序算法。如果有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法——插入排序法,插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。
插入排序分为直接插入排序、二分排序、希尔排序,我们将谈论这三种种排序
2.直接插入排序
直接插入排序(Straight Insertion Sort)是一种最简单的排序方法,其基本操作是将一条记录插入到已排好的有序表中,从而得到一个新的、记录数量增1的有序表。
直接插入插排的基本思想是:当插入第i(i >= 1)时,前面的V[0],V[1],……,V[i-1]已经排好序。这时,用V[I]的排序码与V[i-1],V[i-2],…的排序码顺序进行比较,找到插入位置即将V[i]插入,原来位置上的元素向后顺移。
使用Java实现直接插入排序:
package cn.edu.ccut.sort;
import java.util.Arrays;
/**
* 插入排序-直接插入排序
* 初始序列:[4],2,6,3,1,5
* 第一次排序:[2,4],6,3,1,5
* 第二次排序:[2,4,6],3,1,5
* 第三次排序:[2,3,4,6],1,5
* 第四次排序:[1,2,3,4,6],5
* 第五次排序:[1,2,3,4,5,6]
* @author jwang
*
*/
public class InsertSort {
public static void main(String[] args) {
int [] arr = {4,2,6,3,1,5};//待排序列
System.out.println("排序前:"+Arrays.toString(arr));
insertSort(arr);
System.out.println("排序后:"+Arrays.toString(arr));
}
private static void insertSort(int[] arr) {
for(int i=1;i<arr.length;i++){//除了第一个元素都是待排元素
int temp = arr[i];//待排元素
int j = i;//待排元素索引
//如果j>0且temp<arr[j-1],证明待排元素前一个元素不是起始元素,且待排元素小于前一个元素
while(j > 0 && temp < arr[j-1]){
//满足条件则需要将j位置的元素向后移动一位
arr[j] = arr[j-1];
j--;
}
//将待排元素插入指定位置
arr[j] = temp;
}
}
}
3.二分排序
二分法插入排序,简称二分排序,是在插入第i个元素时,对前面的0~i-1元素进行折半,先跟他们中间的那个元素比,如果小,则对前半再进行折半,否则对后半进行折半,直到left<right,然后再把第i个元素前1位与目标位置之间的所有元素后移,再把第i个元素放在目标位置上。
代码如下:
package cn.edu.ccut.search;
public class Test {
public static void main(String[] args) {
int [] arr = {31,17,15,32,14,28,94,28,65};
System.out.println("排序前:");
traversing(arr);
System.out.println();
binaryInsertSort(arr);
System.out.println("排序后:");
traversing(arr);
}
public static void binaryInsertSort(int[] array){
for(int i = 0;i<array.length;i++){
int temp = array[i];//待插入到前面有序序列的值
int left = 0;//有序序列的左侧
int right = i-1;//有序序列的右侧
int middle = 0;//有序序列的中间
while(left <= right){
middle = (left + right)/2;//赋值
if(temp<array[middle]){
right = middle-1;
}else{
left = middle + 1;
}
}
for(int j = i-1;j>=left;j--){
//从i-1到left依次向后移动一位,等待temp值插入
array[j+1] = array[j];
}
if(left != i ){
array[left] = temp;
}
}
}
//遍历数组
public static void traversing(int [] arr){
for(int num : arr){
System.out.print(num+"\t");
}
}
}
4.希尔排序
希尔排序(Shell's Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因D.L.Shell于1959年提出而得名。
与快速排序是冒泡排序改进版类似,直接插入排序也有改进版,那就是希尔排序。
希尔排序属于插入类排序,是将整个有序序列分割成若干小的子序列分别进行插入排序。
排序过程:先取一个正整数d1<n,把所有序号相隔d1的数组元素放一组,组内进行直接插入排序;然后取d2<d1,重复上述分组和排序操作;直至di=1,即所有记录放进一个组中排序为止。
使用Java实现希尔排序:
package cn.edu.ccut.search;
public class Test {
public static void main(String[] args) {
int [] arr = {31,17,15,32,14,28,94,28,65};
//{14,31},{17,28},{15,94},{28,32},{65}
System.out.println("排序前:");
traversing(arr);
System.out.println();
shellSort(arr);
System.out.println("排序后:");
traversing(arr);
}
//希尔排序
public static void shellSort(int [] arr) {
int n = arr.length;
for(int gap=n/2;gap>0;gap/=2){//产生分组间隔gap
//对每一个分组进行插入排序
for(int i=gap;i<n;i++){
shellSort(arr,gap,i);
}
}
}
private static void shellSort(int[] arr, int gap, int i) {
int temp = arr[i];//待排数字 14
int j = i-gap;//0
while(j>=0 && arr[j]>temp){
arr[j+gap] = arr[j];
j-=gap;
}
arr[j+gap] = temp;
}
//遍历数组
public static void traversing(int [] arr){
for(int num : arr){
System.out.print(num+"\t");
}
}
}