插入排序算法
选择排序
插入排序
插入排序->{直接插入排序,二分插入排序,希尔插入排序}
直接插入排序
原理:设有一组关键字{K1, K2,…, Kn};排序开始就认为 K1 是一个有序序列;让 K2 插入上述表长为 1 的有序序列,使之成为一个表长为 2 的有序序列;然后让 K3 插入上述表长为 2 的有序序列,使之成为一个表长为 3 的有序序列;依次类推,最后让 Kn 插入上述表长为 n-1 的有序序列,得一个表长为 n 的有序序列。
具体算法描述:
- 从第一个元素开始,该元素可以认为已经被排序
- 取下第一个元素, 在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤3,直到找到已排序的元素小于或等于新元素的位置
- 将新元素插入到该位置后
重复步骤2-5
现有一组数组 arr = [5, 6, 3, 1, 8, 7, 2, 4],共有八个记录,排序过程如下:
[5] 6 3 1 8 7 2 4
↑ │
└───┘
[5, 6] 3 1 8 7 2 4
↑ │
└────────┘
[3, 5, 6] 1 8 7 2 4
↑ │
└──────────┘
[1, 3, 5, 6] 8 7 2 4
↑ │
└──┘
[1, 3, 5, 6, 8] 7 2 4
↑ │
└────┘
[1, 3, 5, 6, 7, 8] 2 4
↑ │
└────────────────┘
[1, 2, 3, 5, 6, 7, 8] 4
↑ │
└─────────────┘
[1, 2, 3, 4, 5, 6, 7, 8]
public static void insertSort(int[] a) {
for (int i = 1; i < a.length; i++) //n-1此扫描,依次向前插入n-1个元素
{
int temp = a[i]; //每趟将a[i]插入到前面的排序子序列中
int j;
for (j = i - 1; j >= 0 && temp < a[j]; j--) {
a[j + 1] = a[j]; //将前面较大的元素向后移动
}
a[j + 1] = temp; //temp值到达插入位置
System.out.println(Arrays.toString(a));
}
}
二分查找
11
--------0---------
[1, 2, 9, 11, 31, 42, 47, 17, 3, 10, 15]
--------1---------
curr:2 left:0 right:0 mid_index:0-1
curr:2 left:1 right:0
[1, 2, 9, 11, 31, 42, 47, 17, 3, 10, 15]
--------2---------
curr:9 left:0 right:1 mid_index:0-1
curr:9 left:1 right:1 mid_index:1-2
curr:9 left:2 right:1
[1, 2, 9, 11, 31, 42, 47, 17, 3, 10, 15]
--------3---------
curr:11 left:0 right:2 mid_index:1-2
curr:11 left:2 right:2 mid_index:2-9
curr:11 left:3 right:2
[1, 2, 9, 11, 31, 42, 47, 17, 3, 10, 15]
--------4---------
curr:31 left:0 right:3 mid_index:1-2
curr:31 left:2 right:3 mid_index:2-9
curr:31 left:3 right:3 mid_index:3-11
curr:31 left:4 right:3
[1, 2, 9, 11, 31, 42, 47, 17, 3, 10, 15]
--------5---------
curr:42 left:0 right:4 mid_index:2-9
curr:42 left:3 right:4 mid_index:3-11
curr:42 left:4 right:4 mid_index:4-31
curr:42 left:5 right:4
[1, 2, 9, 11, 31, 42, 47, 17, 3, 10, 15]
--------6---------
curr:47 left:0 right:5 mid_index:2-9
curr:47 left:3 right:5 mid_index:4-31
curr:47 left:5 right:5 mid_index:5-42
curr:47 left:6 right:5
[1, 2, 9, 11, 31, 42, 47, 17, 3, 10, 15]
--------7---------
curr:17 left:0 right:6 mid_index:3-11
curr:17 left:4 right:6 mid_index:5-42
curr:17 left:4 right:4 mid_index:4-31
curr:17 left:4 right:3
数组下标为4的31值为最后查找到的left 然后将下标4-6的值向后移一位 最后与初始数组下标为7的17临时值交换
[1, 2, 9, 11, 17, 31, 42, 47, 3, 10, 15]
--------8---------
curr:3 left:0 right:7 mid_index:3-11
curr:3 left:0 right:2 mid_index:1-2
curr:3 left:2 right:2 mid_index:2-9
curr:3 left:2 right:1
[1, 2, 3, 9, 11, 17, 31, 42, 47, 10, 15]
--------9---------
curr:10 left:0 right:8 mid_index:4-11
curr:10 left:0 right:3 mid_index:1-2
curr:10 left:2 right:3 mid_index:2-3
curr:10 left:3 right:3 mid_index:3-9
curr:10 left:4 right:3
[1, 2, 3, 9, 10, 11, 17, 31, 42, 47, 15]
--------10---------
curr:15 left:0 right:9 mid_index:4-10
curr:15 left:5 right:9 mid_index:7-31
curr:15 left:5 right:6 mid_index:5-11
curr:15 left:6 right:6 mid_index:6-17
curr:15 left:6 right:5
[1, 2, 3, 9, 10, 11, 15, 17, 31, 42, 47]
public static void binaryInsertSort(int[] a) {
for (int i = 1; i < a.length; i++) {
System.out.println("--------" + i + "---------");
int left = 0;
int right = i - 1;
int curr = a[i];
// 利用折半查找插入位置
while (left <= right) {
// 取中点
int mid = (left + right) / 2;
System.out.println("temp:" + curr + " left:" + left + " right:" + right + " mid_index:" + mid + "-" + a[mid]);
// 插入值小于中点值
if (a[mid] > curr) {
// 向左缩小区间
right = mid - 1;
} else {
// 向右缩小区间
left = mid + 1;
}
}
System.out.println("temp:" + curr + " left:" + left + " right:" + right );
// for(int j = i-1; j >= right+1; j--)
// left即为找到的要插入的位置,所以下边的循环将left-(i-1)位置的元素依次向后移动
for (int j = i - 1; j >= left; j--)
{
a[j + 1] = a[j];
}
// 将temp插入到left位置
a[left] = curr;
System.out.println(Arrays.toString(a));
}
}
public static void main(String[] args) {
// int[] a= new int[]{2,5,3,7};
// int[] a = {7, 2, 5, 3, 1, 9, 4};
int[] a = {1, 2, 9, 4, 5, 8, 7, 6, 3, 10, 11};
System.out.println(a.length);
System.out.println("--------0---------");
System.out.println(Arrays.toString(a));
binaryInsertSort(a);
}
希尔排序
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是一种非稳定性排序
可以使得性能提升至O(n log2 n)。这比最好的比较算法的O(n log n)要差一些。
希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。
这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序。
希尔排序又称为缩小增量排序,基本思想是分组的直接插入排序。
由直接插入排序算法分析可知,若数据序列接近有序,则时间效率越高;当n较小时,时间效率也很高。希尔排序基于这两点对直接插入排序进行了改进。
采用间隔4创建四个位置所有值的虚拟列表{35,14},{33,19},{42,27},{10,44}
比较每个子列表中的值,如需要则在原始数组中交换
采用间隔1,产生两个子列表,{14,27,35,42},{19,10,33,44}
比较子列表中的值,如有需要则在原始数组中交换
最后使用间隔1对数组其余部分进行排序
JAVA代码
public static void shellSort(int[] arr) {
int i, j, gap;
// 获得步长
for (gap = arr.length / 2; gap > 0; gap /= 2) {
System.out.println("gap:"+gap);
// 进行插入排序
for (i = 0; i < gap; i++) {
// j每个子列表元素下表
for (j = i + gap; j < arr.length; j += gap) {
if (arr[j] < arr[j - gap]) {
int tmp = arr[j];
int k = j - gap;
while (k >= 0 && arr[k] > tmp) {
arr[k + gap] = arr[k];
k -= gap;
}
arr[k + gap] = tmp;
System.out.println(Arrays.toString(arr));
}
}
}
}
}
https://www.cnblogs.com/snowcan/p/6244391.html
https://blog.csdn.net/qq_36879870/article/details/90512902
https://blog.csdn.net/Fcwyl000/article/details/80465359
https://blog.csdn.net/xxy_hl/article/details/82795526
https://blog.csdn.net/weixin_38333555/article/details/80515605
https://blog.csdn.net/xiazdong/article/details/7304239
https://blog.csdn.net/xiazdong/article/details/8462393