1.简介
插入类排序:顾名思意,即排序过程中,在有序的序列当中插入元素。分为以下三类
2.直接插入排序
2.1 思想
逐个将第n个待排序元素添加到前(n-1)个有序序列当中。
例如:待排序序列为{4, 2, 6, 9, 5, 1, 10, 3, 8, 7},每次从右向左查找元素的插入位置
第1趟:4 2, 6, 9, 5, 1, 10, 3, 8, 7 添加4
第2趟:2 4 6, 9, 5, 1, 10, 3, 8, 7 添加2
第3趟:2 4 6 9, 5, 1, 10, 3, 8, 7 添加6
第4趟:2 4 6 9 5, 1, 10, 3, 8, 7 添加9
第5趟:2 4 5 6 9 1, 10, 3, 8, 7 添加5
第6趟:1 2 4 5 6 9 10, 3, 8, 7 添加1
第7趟:1 2 4 5 6 9 10 3, 8, 7 添加10
第8趟:1 2 3 4 5 6 9 10 8, 7 添加3
第9趟:1 2 3 4 5 6 8 9 10 7 添加8
第10趟:1 2 3 4 5 6 7 8 9 10 添加7
2.2 实现
void direct_insert_sort(vector<int>& nums)
{
for (int j = 1; j < nums.size(); ++j) {
int temp = nums[j];
int k = j-1;
while (k >= 0 && nums[k] > temp) { //查找插入位置
nums[k+1] = nums[k];
--k;
}
nums[k + 1] = temp; //填充插入元素
}
}
2.3 时间和空间复杂度分析
时间复杂度:若当前序列为有序序列,无需进行任何元素的移动,最好时间复杂度为O(n),最坏的情况为倒序的序列,需比较的次数为(1+2+3+...+n) = n*(n-1) / 2,故最坏时间复杂度为O(n^2),故最终的平均复杂度为O(n^2)
空间复杂度:除了一个临时交换变量的空间,无需任何额外的空间,故为O(1)
3.折半查找排序
3.1 思想
采用折半查找待排序元素在前(n-1)个元素有序序列的插入位置。
例如,待排序序列为{4, 2, 6, 9, 5, 1, 10, 3, 8, 7},每次折半查找元素的插入位置
第1趟:4 2, 6, 9, 5, 1, 10, 3, 8, 7 添加4
第2趟:2 4 6, 9, 5, 1, 10, 3, 8, 7 添加2 left = 0, right = 0--->插入位置0
第3趟:2 4 6 9, 5, 1, 10, 3, 8, 7 添加6 left = 0, right = 1---->插入位置2
第4趟:2 4 6 9 5, 1, 10, 3, 8, 7 添加9 left = 0, right = 2---->插入位置3
第5趟:2 4 5 6 9 1, 10, 3, 8, 7 添加5
第6趟:1 2 4 5 6 9 10, 3, 8, 7 添加1
第7趟:1 2 4 5 6 9 10 3, 8, 7 添加10
第8趟:1 2 3 4 5 6 9 10 8, 7 添加3
第9趟:1 2 3 4 5 6 8 9 10 7 添加8
第10趟:1 2 3 4 5 6 7 8 9 10 添加7
3.2 实现
void half_insert_sort(vector<int>& nums)
{
for (int j = 1; j < nums.size(); ++j) {
int left = 0;
int right = j - 1;
int temp = nums[j];
while (left <= right) { //折半查找插入位置
int mid = (left + right) / 2;
if (nums[mid] > temp) right = mid - 1;
else left = mid + 1;
}
right = j - 1;
while (right >= left) { //移动元素
nums[right + 1] = nums[right];
right--;
}
nums[left] = temp;
}
}
3.3 时间和空间复杂度分析
时间复杂度:若当前序列为有序序列,每次只需查找一半,最好时间复杂度为O(n*log(n)),最坏的情况为倒序的序列,需比较的次数为(1+2+3+...+n) = n*(n-1) / 2,故最坏时间复杂度为O(n^2),故最终的平均复杂度为O(n^2)
空间复杂度:除了一个临时交换变量的空间,无需任何额外的空间,故为O(1)
4 希尔排序
4.1 思想
将待排序的序列按照增量分为待排序的子序列,依次缩小增量,重新划分子序列,......,直至增量大小为1,最终的序列即为有序序列.
例如:待排序序列为{4, 2, 6, 9, 5, 1, 10, 3, 8, 7},每次根据增量划分子序列
第1趟:增量为10 / 2 = 5
子序列1:4, 1
子序列2: 2, 10
子序列3: 6, 3
子序列4: 9, 8
子序列5: 5, 7
合并子序列后: 1, 2, 3, 8, 5, 4, 10, 6, 9, 7
第2趟:增量为5 / 2 = 2
子序列1:1, 3, 5, 10, 9
子序列2: 2, 8, 4, 6, 7
排序后: 1, 2, 3, 4, 5, 6, 9, 7, 10, 8
最后一趟后:1, 2, 3, 4, 5, 6, 7, 8, 9, 10
4.2 实现
void different_dis_sort(vector<int>& nums, int start, int dis, int cur)
{
int t = nums[cur];
cur -= dis;
while (cur >= start && nums[cur] > t) { //局部的直接插入排序
nums[cur + dis] = nums[cur];
cur -= dis;
}
nums[cur + dis] = t;
}
void hill_insert_sort(vector<int>& nums)
{
int dis = log2(nums.size() - 1);
while (dis >= 1) {
int start = 0;
while (start < dis) {
int cur = start + dis;
while (cur < nums.size()) {
different_dis_sort(nums, start, dis, cur);
cur += dis;
}
start++; //下一个位置开始
}
//dis /= 2; //希尔增量
dis = log2(dis); //帕和斯增量
cout << dis << endl;
}
}
4.3 时间和空间复杂度分析
时间复杂度:取决于增量的选取,若采用希尔增量(n/2),最终的时间复杂度为O(n^2);若采用papernov&Stasevich增量(log(n)),时间复杂度为O(n^1.5)
空间复杂度:除了一个临时交换变量的空间,无需任何额外的空间,故为O(1)
[1]数据结构清华大学版
[2]数据结构高分笔记