数据结构:冒泡排序,选择排序,插入排序,希尔排序的实现分析

本文主要是介绍数据结构:冒泡排序,选择排序,插入排序,希尔排序的实现分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

✨✨小新课堂开课了,欢迎欢迎~✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:数据结构与算法

小新的主页:编程版小新-CSDN博客

 1.冒泡排序

1.1算法思想

冒泡排序的基本思想就是,遍历原数组的元素,比较相邻的两个元素,如果这两个元素的顺序不对,就是把这两个元素交换,直到都不需要交换的时候,排序结束。

1.2具体步骤

比较相邻的两个元素,把大的(小的)往后换,就这样重复此步骤,每遍历完数组一次,就能将最大的(最小的)元素放在最后。重复遍历该数组,直至都不需要交换的时候,排序就结束了。

1.3动图演示

24年-05月27日--排序/动图/冒泡排序.gif

1.4代码实现

void Swap(int*a,int*b)
{int tmp = *a;*a = *b;*b = tmp;
}
//冒泡排序
void BubbleSort(int* arr, int len)
{for (int i = 0; i < len - 1; i++)//比较次数{for (int j = 0; j < len-1-i; j++)//单趟比较{if (arr[j] > arr[j + 1]){Swap(&arr[j], &arr[j + 1]);}}}
}

有的时候不用遍历数组len次,排序就已经排好了,我们知道遍历完数组一次后,如果不存在交换,那就不用再继续比较了。此时排序已经排好了。

优化:

void Swap(int*a,int*b)
{int tmp = *a;*a = *b;*b = tmp;
}
//冒泡排序
void BubbleSort(int* arr, int len)
{int flag = 0;for (int i = 0; i < len - 1; i++)//比较次数{for (int j = 0; j < len-1-i; j++)//单趟比较{if (arr[j] > arr[j + 1]){Swap(&arr[j], &arr[j + 1]);flag = 1;}}if(flag ==0)//未发生交换,排序已经完成break;}
}

1.5复杂度分析

时间复杂度:这里很容易就能看出来是O(N^2)。以最坏的情况来看,n-1+n-2+n-3+……+2+1=n*(n-1)/2。

空间复杂度: 因为没有额外的开空间,所以空间复杂度为O(1)。

1.6稳定性分析

稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

简而言之,相同值相对位置不变称之为稳定。

 冒泡排序是相邻位置的元素比较,决定交不交换,一样的元素,在排序过程中相对位置不会发生变化,因此冒泡排序是稳定的

2.选择排序

2.1算法思想

遍历原数组,找出最小或者最大的那个元素,与起始位置或则末尾的元素交换,每遍历完一次,起始位置向后移(末尾的位置往前移),当起始位置移到最后一个位置时(末尾位置移到数组的第一个元素的位置时),排序结束。

2.2具体步骤

遍历数组,找到最大或者最小的元素,与起始位置交换。

从剩余的元素中找继续找最大或最小的元素,排到已排序序列的末尾。

以此类推,直到所有的元素都排列完毕。

2.3动图演示

2.4代码实现

基于动态演示实现的代码:

void SelectSort(int* arr, int len)//选择排序
{for (int i = 0; i < len - 1; i++)//起始位置{int mini = i;for (int j = i + 1; j < len; j++)//寻找最小元素{if (arr[j] < arr[mini]){mini = j;}}swap(&arr[mini], &arr[i]);}
}

上面的代码效率比较低,我们在遍历一遍数组的时候,可以找到该数组中最大和最小的元素,让最大的元素与end交换,最小的元素与begin交换,不断的这样缩小区间,完成排序。

这里要注意的是,我们在交换的时候,可能会改变最大或最小元素的位置 。

//选择排序void Swap(int*a,int*b)
{int tmp = *a;*a = *b;*b = tmp;
}void SelectSort(int* arr, int len)
{int begin = 0;int end = len - 1;while (begin < end){int mini = begin;int maxi = begin;for (int i = begin + 1; i <=end; i++){//遍历一遍找最大和最小if (arr[i] > arr[maxi]){maxi = i;}if (arr[i] < arr[mini]){mini = i;}}Swap(&arr[begin], &arr[mini]);if (maxi == begin)//如果begin和maxi重合,就要对maxi更正{maxi = mini;}Swap(&arr[end], &arr[maxi]);begin++;end--;}
}

2.5复杂度分析

时间复杂度:优没优化,算时间复杂度的时候都是等差数列,时间复杂度为O(N^2)。

空间复杂度:没有额外开辟空间,因此空间复杂度为O(N)。

2.6稳定性分析

3.插入排序

3.1算法思想

把待排元素逐一与已排序的部分元素进行比较,把它插入到已排序序列中的适当位置,直到把元素全部插入完毕。

3.2具体步骤

把第一个元素看成有序序列,从第二个元素开始,将该元素与前面已排好序的元素比较,如果该元素比较小,就将前面的元素依次往后移动一位,将该元素插入到腾出的位置上。

重复上面的插入过程,直至整个序列都被排序完成。

3.3动图演示

3.4代码实现

// 插入排序
void InsertSort(int* a, int n)
{//【0-end】有序,将end+1的值插入到区间内,形成新的区间for (int i = 0; i < n - 1; i++){int end = i;int tmp = a[end + 1];while (end >= 0){if (a[end] > tmp){a[end + 1] = a[end];//往后移end--;}else{break;//找到合适的位置了//也有可能合适的位置就是数组的起始位置,没有进break,此时end为-1越界,在// end+1的位置插入,就是把该元素插入到起始位置}}a[end + 1] = tmp;//在腾出来的位置插入该元素}}

3.5复杂度分析

时间复杂度:以最坏的情况,逆序来算,移动的次数是等差数列的前n-1项和,O(N^2)。

空间复杂度:没有额外开辟空间,空间复杂度为O(1)。

3.6稳定性分析

插入排序不会改变相同元素的相对位置,在前面的和在后面的那个在插入到腾出的位置后,还是一前一后。因此插入排序稳定

4.希尔排序

4.1算法思想

希尔排序是对插入排序的改进。它先将整个待排的序列分割成若干个子序列,对每一个子序列分别进行插入排序,然后不断缩小缩小子序列的间隔,重复这个过程直至间隔为1 时进行一次完整的插入排序。

4.2具体步骤

希尔排序分为两步:1.预排序(使数组接近有序) 2.插入排序

选取一个gap,间隔gap个数据为一组,把整个数组进行分组,一共gap组。

以gap为基准,对其进行插入排序。

不断缩小gap,直至gap为1,进行一次完整的插入排序。

gap>1时是在进行预排序,gap==1是在进行直接插入排序。          

4.3动图演示

4.4代码实现

// 希尔排序
//希尔排序分为两步:第一步是预排序(使其接近有序),第二步是进行插入排序
void ShellSort(int* a, int n)
{int gap = n;//gap代表每间隔gap个为一组即一共分成gap组while (gap > 1){//gap>1是进行预排序//gap==1是在进行插入排序gap = gap / 3 + 1;//+1是保证最后一组gap一定为1,for (int i = 0; i < n - gap; i++){int end = i;int tmp = a[end + gap];//i之所以小于n-gap;是防止这里越界while (end >= 0){if (a[end] > tmp){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}
}

4.5复杂度分析

时间复杂度:希尔排序的时间复杂度可以直接记,因为比较难算。O(N^1.3)

空间复杂度:没有额外开辟空间,空间复杂度为O(1)。

4.6稳定性分析

在排序过程中,可能相同数据分到不同的组,这个无法控制,因此希尔排序不稳定

这篇关于数据结构:冒泡排序,选择排序,插入排序,希尔排序的实现分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1067996

相关文章

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

Python中的Walrus运算符分析示例详解

《Python中的Walrus运算符分析示例详解》Python中的Walrus运算符(:=)是Python3.8引入的一个新特性,允许在表达式中同时赋值和返回值,它的核心作用是减少重复计算,提升代码简... 目录1. 在循环中避免重复计算2. 在条件判断中同时赋值变量3. 在列表推导式或字典推导式中简化逻辑

Python位移操作和位运算的实现示例

《Python位移操作和位运算的实现示例》本文主要介绍了Python位移操作和位运算的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 位移操作1.1 左移操作 (<<)1.2 右移操作 (>>)注意事项:2. 位运算2.1

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依