希尔排序(缩小增量排序)(插入排序的优化版) C++代码实现及算法分析 恋上数据结构笔记
文章目录
- 复习概要
- 算法思想
- 算法流程
- 算法复杂度分析及稳定性
- 希尔排序代码正常版
- 希尔排序与插入排序代码对比
- 希尔排序个人青春版(别看以免走上歧途)
复习概要
- 算法思想与流程
- 分这么多组分别插入排序有什么用?为什么不直接整个插入排序?
- 时间复杂度
- 优化
- 要眼熟插入排序那一段的代码,和原本的插入排序对比着看!
- 插入排序那一段多了一层循环是干什么的,怎么是三层循环?
- 希尔的步长序列生成方式?
算法思想
- 我觉得完全没必要按照行和列的思想去理解希尔排序
- 因为一句话概括希尔排序就是,每隔几个元素一组,分组进行插入排序,然后重新分组,直到每个元素都是一组
- 内层先标记这是第几组,然后就是最简单的插入排序思想,只不过是对同一组(列)里的元素的插入排序,请想象元素之间的距离变成stepSequence了,不是1了,而且组的第一个元素索引是col(第几组,初始为0)不是0了,第一个无序元素的位置就是col+stepSequence了,把所有组分别进行插入排序就结束了
- 外层就是不断缩小分组所需的步长(元素增量),然后循环内层
- 步长:就是隔几个一组
- 建议和普通插入排序的代码结合着看,很容易就理解了
- 话说希尔排序居然是用发明者名字命名的
- 希尔排序比之间插入排序强的地方是,总共处理的逆序对数量比直接插入排序少了,每次分组排序同时会解决一些额外的逆序对。
算法流程
输入数组:
29 15 12 10 9 8 7 6 5 3 2 1
希尔排序正常版
(每隔几个元素就取出一个看作一组)(也就是列)步长为6,每组有length/步长 个元素
[29] 15 12 10 9 8 [7] 6 5 3 2 1
7 [15] 12 10 9 8 29 [6] 5 3 2 1
7 6 [12] 10 9 8 29 15 [5] 3 2 1
7 6 5 [10] 9 8 29 15 12 [3] 2 1
7 6 5 3 [9] 8 29 15 12 10 [2] 1
7 6 5 3 2 [8] 29 15 12 10 9 [1]
7 6 5 3 2 1 29 15 12 10 9 8
(每隔几个元素就取出一个看作一组)(也就是列)步长为3
[7] 6 5 [3] 2 1 [29] 15 12 [10] 9 8
3 [15] 12 7 [9] 8 10 [6] 5 29 [2] 1
3 2 [12] 7 6 [8] 10 9 [5] 29 15 [1]
3 2 1 7 6 5 10 9 8 29 15 12
(每隔几个元素就取出一个看作一组)(也就是列)步长为1
[3] [2] [1] [7] [6] [5] [10] [9] [8] [29] [15] [12]
1 2 3 5 6 7 8 9 10 12 15 29
算法复杂度分析及稳定性
希尔排序最好时间复杂度和插入排序相同为O(n)
最坏时间复杂度和平均时间复杂度取决于步长序列
希尔本人的步长序列生成法(length/2的k次幂)最坏时间复杂度为O(n2),目前最好的最坏时间复杂度的步长序列生成法可以做到O(n的4/3次方),如下,k=1,2,3.。。。注意是最坏时间复杂度(even代表奇数,odd代表偶数)
希尔排序不稳定,空间复杂度O(1),为原地算法
希尔排序代码正常版
//产生步长序列(按照希尔本人的生成方式)
void stepSequenceGenerator(vector<int> array, vector<int> &stepSequence)
{for (int i = 2; i < array.size(); i = i * 2){stepSequence.push_back(array.size() / i);}
}void sort(vector<int> array, int stepSequence)
{//col:当前是第几组(列)for (int col = 0; col < stepSequence; col++){//下面其实就是最简单的插入排序的代码,只不过是对同一组(列)里的元素的插入排序//请想象元素之间的距离变成stepSequence了,不是1了,而且组的第一个元素索引是col不是0了,第一个无序元素的位置就是col+stepSequence了for (int chaosBeginIndex = col + stepSequence; chaosBeginIndex < array.size(); chaosBeginIndex = chaosBeginIndex + stepSequence){for (int insertEIndex = chaosBeginIndex; insertEIndex > col; insertEIndex = insertEIndex - stepSequence){if (array[insertEIndex] < array[insertEIndex - stepSequence]){int temp = array[insertEIndex];array[insertEIndex] = array[insertEIndex - stepSequence];array[insertEIndex - stepSequence] = temp;}}}vectorPrint(array);}
}void shellSort(vector<int> &array)
{vector<int> stepSequence;stepSequenceGenerator(array, stepSequence);for (int i = 0; i < stepSequence.size(); i++){cout << "(每隔几个元素就取出一个看作一组)(也就是列)步长为" << stepSequence[i] << endl;sort(array, stepSequence[i]);}
}
输入数组:
29 15 12 10 9 8 7 6 5 3 2 1
希尔排序正常版
(每隔几个元素就取出一个看作一组)(也就是列)步长为6
7 15 12 10 9 8 29 6 5 3 2 1
7 6 12 10 9 8 29 15 5 3 2 1
7 6 5 10 9 8 29 15 12 3 2 1
7 6 5 3 9 8 29 15 12 10 2 1
7 6 5 3 2 8 29 15 12 10 9 1
7 6 5 3 2 1 29 15 12 10 9 8
(每隔几个元素就取出一个看作一组)(也就是列)步长为3
3 15 12 7 9 8 10 6 5 29 2 1
3 2 12 7 6 8 10 9 5 29 15 1
3 2 1 7 6 5 10 9 8 29 15 12
(每隔几个元素就取出一个看作一组)(也就是列)步长为1
1 2 3 5 6 7 8 9 10 12 15 29
算法用时:(微秒)
[AlgoTime: 12002 us]
希尔排序与插入排序代码对比
void sort2nd(vector<int> array, int stepSequence)
{//col:当前是第几组(列)for (int col = 0; col < stepSequence; col++){//下面其实就是最简单的插入排序的代码,只不过是对同一组(列)里的元素的插入排序//请想象元素之间的距离变成stepSequence了,不是1了,而且组的第一个元素索引是col不是0了,第一个无序元素的位置就是col+stepSequence了for (int chaosBeginIndex = col + stepSequence; chaosBeginIndex < array.size(); chaosBeginIndex = chaosBeginIndex + stepSequence){for (int insertEIndex = chaosBeginIndex; insertEIndex > col; insertEIndex = insertEIndex - stepSequence){if (array[insertEIndex] < array[insertEIndex - stepSequence]){int temp = array[insertEIndex];array[insertEIndex] = array[insertEIndex - stepSequence];array[insertEIndex - stepSequence] = temp;}}}vectorPrint(array);}
}void insertionSort1th(vector<int> &array) //这里以数组左侧作为有序的那一边
{// chaosBeginIndex:未排序序列的起始元素下标// insertEIndex:拿去插入有序序列的那个元素的下标,就是未排序序列的起始元素,但随着交换位置,下标会改变for (int chaosBeginIndex = 1; chaosBeginIndex < array.size(); chaosBeginIndex++)//外循环控制从第二个元素开始插入到有序序列里,直到最后一个元素{for (int insertEIndex = chaosBeginIndex; insertEIndex > 0; insertEIndex--)//内循环控制从未排序序列的首元素开始,逐渐与有序序列元素比较和交换位置,找到有序序列中的合适位置{if (array[insertEIndex] < array[insertEIndex - 1]){int temp = array[insertEIndex];array[insertEIndex] = array[insertEIndex - 1];array[insertEIndex - 1] = temp;}else{break;}}vectorPrint(array);}
}
希尔排序个人青春版(别看以免走上歧途)
看输出就能看出来,我改写了插入排序,可以自由选择一段进行插入排序,然后又建了一个空容器,把元素按组排序压入容器,然后覆盖主数组,但是毫无意义,看输出就知道,把一组元素放到一起又会导致不同组之间产生新的逆序对
void insertionSort1th(vector<int> &array, int begin, int end) //这里以数组左侧作为有序的那一边
{// chaosBeginIndex:未排序序列的起始元素下标// insertEIndex:拿去插入有序序列的那个元素的下标,就是未排序序列的起始元素,但随着交换位置,下标会改变for (int chaosBeginIndex = begin + 1; chaosBeginIndex <= end; chaosBeginIndex++)//外循环控制从第二个元素开始插入到有序序列里,直到最后一个元素{for (int insertEIndex = chaosBeginIndex; insertEIndex > begin; insertEIndex--)//内循环控制从未排序序列的首元素开始,逐渐与有序序列元素比较和交换位置,找到有序序列中的合适位置{if (array[insertEIndex] < array[insertEIndex - 1]){int temp = array[insertEIndex];array[insertEIndex] = array[insertEIndex - 1];array[insertEIndex - 1] = temp;}else{break;}}}
}void sort(vector<int> &array, int stepSequence)
{vector<int> temp;for (int j = 0; j < stepSequence; j++){int i = 0;for (int index = j; index < array.size(); index = index + stepSequence){temp.push_back(array[index]);i = i + 1;}insertionSort1th(temp, temp.size() - i, temp.size() - 1);vectorPrint(temp);}array = temp;
}void shellSort(vector<int> &array)
{vector<int> stepSequence;stepSequenceGenerator(array, stepSequence);for (int i = 0; i < stepSequence.size(); i++){cout << "(每隔几个元素就取出一个看作一组)(也就是列)步长为" << stepSequence[i] << endl;sort(array, stepSequence[i]);}
}
输入数组:
29 15 12 10 9 8 7 6 5 3 2 1
希尔排序个人青春版
(每隔几个元素就取出一个看作一组)(也就是列)步长为6
7 29
7 29 6 15
7 29 6 15 5 12
7 29 6 15 5 12 3 10
7 29 6 15 5 12 3 10 2 9
7 29 6 15 5 12 3 10 2 9 1 8
(每隔几个元素就取出一个看作一组)(也就是列)步长为3
3 7 9 15
3 7 9 15 1 5 10 29
3 7 9 15 1 5 10 29 2 6 8 12
(每隔几个元素就取出一个看作一组)(也就是列)步长为1
1 2 3 5 6 7 8 9 10 12 15 29
算法用时:(微秒)
[AlgoTime: 9002 us]
希尔排序(缩小增量排序)(插入排序的优化版) C++代码实现及算法分析 恋上数据结构笔记相关推荐
- 计数排序及其改进 C++代码实现与分析 恋上数据结构笔记
文章目录 复习梗概 算法思想 基础思想 改进空间复杂度,改进不能对负数进行排序问题 改进稳定性 计数排序时间空间复杂度 计数排序基础版 代码及输出 计数排序第一次改进版 代码及输出 计数排序终极版 代 ...
- 数据结构之插入排序:希尔排序(缩小增量排序)
排序算法:希尔排序.缩小增量排序 思维导图: 希尔排序的定义: 例: 希尔排序d的选取: 希尔排序的代码实现: 希尔排序的性能: 思维导图: 希尔排序的定义: 普通的插入算法正序时时间复杂度会很小,但 ...
- 插入排序算法 及其二分搜索优化版 C++代码实现 恋上数据结构笔记
复习梗概 文章目录 复习梗概 插入排序算法思想 插入排序时间复杂度与特性(多少,与什么有关?) 插入排序基础版 插入排序2nd优化版(优化了哪里?) !!!插入排序二分搜索优化版(优化了哪里?如何优化 ...
- 堆排序 C++代码实现及思想 排序过程输出 恋上数据结构笔记
复习梗概 文章目录 复习梗概 什么是堆思想? 堆排序算法怎么来的? 什么是下滤?代码 什么是建堆?代码 堆排序本体 代码及排序过程输出 和时间复杂度 完整代码 什么是堆思想? 最大堆:树形结构,每一个 ...
- 快速排序 C++代码实现及其算法思想及时间复杂度分析及优化 恋上数据结构笔记
文章目录 复习梗概 算法思想 算法复杂度分析及稳定性 如何优化? 快速排序改进版代码C++ 快速排序个人青春版代码 完整代码 复习梗概 算法思想,别的排序名字直接就能让人联想到它的算法思想,唯独快速排 ...
- 选择排序 C++代码实现及性能分析 恋上数据结构笔记
文章目录 复习梗概 算法思想及时间复杂度 选择排序的优化 代码及输出 完整代码 复习梗概 选择排序算法图解 选择排序在什么地方进行元素的调换 选择排序在什么地方优化,优化后的算法 时间复杂度分析 算法 ...
- ReviewForJob——希尔排序(缩小增量排序)之塞奇威克增量序列
[0]README 0)希尔排序是基于插入排序的.将插入排序算法 内for循环中的所有 1 改为增量就可以..bingo.. 插入排序源码 1)本文旨在给出 希尔排序(缩小增量排序)之塞奇威克增量序列 ...
- 排序算法之希尔排序(缩小增量排序)
前面两篇介绍了两个非常简单又非常基础的算法--选择排序和插入排序,并通过一篇关于大乐透的小应用程序介绍了插入排序的一个简单应用.本篇介绍一个基于插入排序算法的.快速的排序算法--希尔排序.同样,本篇主 ...
- 【恋上数据结构】排序算法前置知识及代码环境准备
排序准备工作 何为排序? 何为稳定性? 何为原地算法? 时间复杂度的知识 写排序算法前的准备 项目结构 Sort.java Asserts.java Integers.java Times.java ...
最新文章
- Jquery前端分页插件pagination同步加载和异步加载
- 第十六届全国大学生智能车竞赛线上比赛(广东+西南科技大学)成绩排名与获奖信息
- 跟老杨学java系列(一)前传
- 文件包含——概念(一)
- 使用JavaCV进行手和手指检测
- jenkins 安装插件失败_Jenkins 自动化安装插件
- 进程和应用程序生命周期
- 大数据:知识,真正的价值体现
- kafka是如何创建topic的
- java nio 多路复用_JAVA NIO 一步步构建I/O多路复用的请求模型
- 阿里面试失败后,一气之下我图解了Java中18把锁
- oracle删除行 锁表,oracle锁表
- OpenCV 视频捕捉
- 运行IE显示“该文件没有程序与之关联来执行该操作”
- swiper设置autoplay不起作用
- 洛谷日报索引(2020、2019、2018)
- html如何查看json数据,浏览器如何查看json格式的数据?查看方法分享
- 完全背包问题(f m)
- 水题Eating Soup
- mysql用insert into select 语句插入数据