【数据结构入门】排序算法之插入排序与选择排序

目录

前言

一、排序的概念及运用

1.排序的概念

2.排序的运用

3.常见排序算法

二、插入排序与选择排序

2.1插入排序

2.1.1直接插入排序

1)基本思想

2)具体步骤

3)算法特性

4)算法实现

2.1.2希尔排序

1)  基本思想

2)具体步骤

3)算法特性

4)算法实现

2.2选择排序

2.2.1直接选择排序

1)  基本思想

2)具体步骤

3)算法特性

4)算法实现

 2.2.2 堆排序

1)  基本思想

2)具体步骤

3)算法特性

4)算法实现

三、算法复杂度及稳定性分析

总结


前言

在数据结构中,排序是指将一组数据按照特定的规则重新排序的过程。排序可以使数据按照升序或者降序排列,从而方便后续的操作和查找。

一、排序的概念及运用

1.排序的概念

排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。

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

例如:

内部排序:数据元素全部放在内存中的排序。

外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

2.排序的运用

排序在生活中的使用无处不在,成绩排名、商品排名、电影榜单等等数不胜数。

 

3.常见排序算法

 

二、插入排序与选择排序

2.1插入排序

2.1.1直接插入排序

1)基本思想

直接插入排序是一种简单的排序算法,它的基本思想是将待排序的数据分成已排序和未排序两部分,每次从未排序部分中取出一个元素,然后将其有序地插入到已排序部分的合适位置。

当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移

动画演示:

2)具体步骤
  1. 将第一个元素视为已排序部分,将剩余的元素视为未排序部分。

  2. 从未排序部分取出第一个元素,将其插入到已排序部分的合适位置。插入时,从后往前逐个比较已排序部分的元素,将大于待插入元素的元素依次后移,直到找到一个小于或等于待插入元素的位置。

  3. 重复步骤2,直到未排序部分中的所有元素都插入到已排序部分。

3)算法特性
  1. 元素集合越接近有序,直接插入排序算法的时间效率越高

  2. 时间复杂度:直接插入排序的时间复杂度是O(n^2),其中n是待排序数据的个数。当输入数据已经基本有序时,直接插入排序的性能较好,时间复杂度可以降低到O(n)。但当输入数据完全逆序时,直接插入排序的性能较差,时间复杂度会达到最大值O(n^2)。

  3. 空间复杂度:O(1),它是一种稳定的排序算法

  4. 稳定性:稳定

4)算法实现
void InsertSort(int* a, int n)
{for (int i = 0; i < n; i++){int end = i-1;int tmp = a[i];//将tmp插入到[0, end]区间中,保持有序while (end >= 0){if (tmp < a[end]){a[end + 1] = a[end];--end;}else{break;}}a[end + 1] = tmp;}	
}

2.1.2希尔排序

希尔排序法又称缩小增量法。

1)  基本思想

将待排序的数据按照一定的增量分组,对每组数据进行插入排序,然后逐渐减小增量,重复上述步骤,直至增量为1,完成最后一轮的插入排序。

图示:

2)具体步骤
  1. 选择一个增量序列,常用的增量序列是希尔增量(N/2, N/4, N/8...,直到增量为1)。

  2. 对于每个增量,以增量作为间隔将待排序的数据分成多个组,分别对每个组进行插入排序。

  3. 逐渐减小增量,重复上述步骤,直至增量为1。

3)算法特性
  1. 希尔排序是对直接插入排序的优化。

  2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。

  3. 希尔排序的时间复杂度较为复杂,最好情况下为O(n log^2 n),最坏情况下为O(n^2),平均情况下为O(n log n)。希尔排序的性能优于直接插入排序,尤其是对于数据量较大的情况,其性能优势更加明显。这里一般可以认为时间复杂度为O(N^1.3)左右。

  4. 稳定性:不稳定

4)算法实现

多组同时排法:

void ShellSort(int* a, int n)
{//预处理int gap = n;while (gap > 1){//这里必须保证gap最后一次是1//gap /= 2;gap = gap / 3 + 1;for (int i = gap; i < n; i++){int end = i - gap;int tmp = a[end + gap];while (end >= 0){if (tmp < a[end]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}	
}

 排完一组再排下一组:

void ShellSort(int* a, int n)
{//预处理int gap = n;while (gap > 1){//这里必须保证gap最后一次是1//gap /= 2;gap = gap / 3 + 1;for (int j = 0; j < gap; j++){for (int i = gap+j; i < n; i += gap){int end = i - gap;int tmp = a[end + gap];while (end >= 0){if (tmp < a[end]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}}	
}

2.2选择排序

2.2.1直接选择排序

1)  基本思想

每一次从待排序的数据中选择最小(或最大)的元素,放到已排序序列的末尾,直到全部待排序的数据元素排完 。

动画演示:

2)具体步骤
  1. 找到待排序序列中最小(或最大)的元素,记为A。

  2. 将A与待排序序列的第一个元素交换位置。

  3. 然后在剩余的待排序序列中找到最小(或最大)的元素,再与待排序序列的第二个元素交换位置。

  4. 重复上述步骤,直到待排序序列变为空。

3)算法特性
  1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用

  2. 时间复杂度:直接选择排序的时间复杂度是O(n^2),无论输入数据的情况如何,都需要进行n-1次的比较和若干次元素交换。虽然直接选择排序的时间复杂度较高,但是它的优点是原地排序,不需要额外的空间。

  3. 空间复杂度:O(1)

  4. 稳定性:不稳定

4)算法实现
void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}void SelectSort(int* a, int n)
{int left = 0, right = n - 1;while (left < right){int mini = left, maxi = left;for (int i = left + 1; i <= right; i++){if (a[i] < a[mini]){mini = i;}if (a[i] > a[maxi]){maxi = i;}}Swap(&a[left], &a[mini]);//如果left和maxi重叠,交换后修正一下,否则这里会出问题,换两次换回去了if (maxi == left){maxi = mini;}Swap(&a[right], &a[maxi]);left++;right--;}
}

 2.2.2 堆排序

堆排序是一种利用堆的数据结构进行排序的算法。堆是一种特殊的二叉树,满足堆性质:任意节点的值都大于等于(或小于等于)其子节点的值。需要注意的是排升序要建大堆,排降序建小堆。

1)  基本思想

将待排序的数据构造成一个堆,然后将堆顶元素与末尾元素交换,再对剩余的元素重新构造堆,以此类推,最终得到有序的序列。

2)具体步骤
  1. 构建最大堆(或最小堆),将待排序的数据转换为堆。

  2. 将堆顶元素(即最大值或最小值)与堆的最后一个叶子节点交换位置。

  3. 重新调整堆,将堆顶元素下沉,使得堆仍然满足堆性质。

  4. 重复上述步骤,直到堆只剩一个元素或为空。

3)算法特性
  1. 堆排序使用堆来选数,效率就高了很多。

  2. 时间复杂度:堆排序的时间复杂度是O(nlogn),堆的构建需要O(n)的时间,每次调整堆的时间为O(logn)。堆排序是一种原地排序算法,不需要额外的空间。由于堆排序具有良好的局部性,适合用于大规模数据的排序。

  3. 空间复杂度:O(1)

  4. 稳定性:堆排序是一种不稳定的排序算法,相同元素的相对位置可能会改变。

4)算法实现
void ADjustDown(int* a, int sz, int parent)
{int child = parent * 2 + 1;while (child < sz){//选出左右孩子中大的一个//这里child+1的判断在前,不要先访问再判断//这里a[child + 1] > a[child] 建大堆用>, 建小堆用<if (child + 1 < sz && a[child + 1] > a[child]){//这地方可能会越界++child;}//这里a[child] > a[parent] 建大堆用>, 建小堆用<if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}void HeapSort(int* a, int sz)
{//1.建堆 -- 向上调整建堆   NlogN//左右子树必须是大堆/小堆/*for (int i = 1; i < sz; i++){ADjustUp(a, i);}*///2.向下调整建堆  N//左右子树必须是大堆/小堆for (int i = (sz - 1 - 1) / 2; i >= 0; i--){ADjustDown(a, sz, i);}int end = sz - 1;while (end > 0){Swap(&a[end], &a[0]);ADjustDown(a, end, 0);--end;}
}

堆排序在前文中已经详细介绍了,具体见: 

【数据结构入门】二叉树之堆排序及链式二叉树

三、算法复杂度及稳定性分析

 

总结

        排序算法的选择可以根据数据的特点、数据量以及排序的要求来确定。不同的排序算法具有不同的时间复杂度和空间复杂度,因此在实际应用中需要根据具体情况选择合适的排序算法。

直接插入排序:

  • 直接插入排序是一种简单直观的排序算法,其思想是将待排序的序列分为已排序和未排序两部分,每次从未排序部分选择一个元素插入到已排序部分的合适位置,直到所有元素都插入到已排序部分为止。
  • 直接插入排序的时间复杂度为O(n^2),是稳定的排序算法。

希尔排序:

  • 希尔排序是直接插入排序的一种改进算法,其核心思想是通过多次分组插入排序,每次对间隔较远的元素进行插入排序,逐步缩小间隔直到间隔为1,最后进行一次完整的插入排序。
  • 希尔排序的时间复杂度取决于间隔序列的选择,一般为O(nlogn),是不稳定的排序算法。

直接选择排序:

  • 直接选择排序是一种简单直观的排序算法,其思想是每次从未排序的序列中选择最小(或最大)的元素,将其与未排序部分的第一个元素交换位置,直到所有元素都排序完成。
  • 直接选择排序的时间复杂度为O(n^2),是不稳定的排序算法。

堆排序:

  • 堆排序利用二叉堆这种数据结构进行排序,将待排序的元素依次插入到堆中,然后从堆顶依次取出最大(或最小)的元素,直到所有元素都取出为止。
  • 堆排序的时间复杂度为O(nlogn),是不稳定的排序算法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1523337.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

草原灭火车的功能与性能_鼎跃安全

在内蒙古的草原火灾中&#xff0c;水陆两栖全地形草原灭火车曾多次用于紧急救援。其强大的越野能力和高速反应&#xff0c;使其在广袤的草原上能够迅速到达火场&#xff0c;并使用集成的多功能灭火设备进行灭火作业&#xff0c;有效防止了火灾的进一步蔓延。 水陆两栖全地形草原…

React学习-hooks

官方文档&#xff1a;https://zh-hans.react.dev/reference/react/useActionState 1.useEffect(setup, dependencies?) 1.1 基础使用 //hooks import { useEffect } from "react"; import "./App.css";function App(){useEffect(()>{console.log(us…

redis的共享session应用

项目背景&#xff1a; 该项目背景就是黑马的黑马点评项目。 一&#xff1a;基于Session实现验证码登录流程 基本的登录流程我们做了很多了。这个是短信登录流程 其实和普通的登录流程就多了一个生成验证码&#xff0c;并将验证码保存在session中&#xff0c;并且呢&#xf…

vue3中使用supermap icilent3d for cesium

记录从头开始学习supermap icilent3d fro cesium 1.新建vue3项目 npm create vitelatest 添加这个&#xff0c;自动打开浏览器 2.使用supermap icilent3d for Cesium 复制这个Cesium&#xff0c;放到pulibc目录下面 然后分别引入css和js 然后就可以使用了&#xff0c;但是会…

Oracle 客户端 PL/SQL Developer 15.0.4 安装与使用

目录 官网下载与安装 切换中文与注册 连接Oracle数据库 tnsnames.ora 文件使用 Oracle 客户端 PL/SQL Developer 12.0.7 安装、数据导出、Oracle 执行/解释计划、for update。 官网下载与安装 1、官网&#xff1a;https://www.allroundautomations.com/products/pl-sql-d…

【STM32】通用定时器TIM(输出比较)

本篇博客重点在于标准库函数的理解与使用&#xff0c;搭建一个框架便于快速开发 目录 前言 输出比较简介 PWM简介 输出比较配置 初始化IO口 输出比较初始化 输出比较代码 PWM.h PWM.c main.c 应用案例 前言 建议先阅读这篇博客&#xff0c;理解时基单元的配置 【…

CDGA|数据治理:构建高效数据管理体系的实践路径

在当今数字化时代&#xff0c;数据已成为企业最宝贵的资产之一&#xff0c;其质量、安全性和有效利用率直接影响着企业的决策能力、运营效率和市场竞争力。因此&#xff0c;数据治理作为确保数据质量、促进数据价值最大化的关键环节&#xff0c;其重要性日益凸显。本文将从几个…

机械学习—零基础学习日志(概率论总笔记1)

概率论的起源 在历史上有明确记载的最早研究随机性的数学家是帕斯卡和费马。帕斯卡就是最早发明机械计算机的那位数学家&#xff0c;他并不是赌徒&#xff0c;但是他有些赌徒朋友&#xff0c;那些人常常玩一种掷骰子游戏&#xff0c;游戏规则是由玩家连续掷4次骰子&#xff0c…

【王树森】Vision Transformer (ViT) 用于图片分类(个人向笔记)

图片分类任务 给定一张图片&#xff0c;现在要求神经网络能够输出它对这个图片的分类结果。下图表示神经网络有40%的信心认定这个图片是狗 ResNet&#xff08;CNN&#xff09;曾经是是图像分类的最好模型在有足够大数据做预训练的情况下&#xff0c;ViT要强于ResNetViT 就是Tr…

(十五)SpringCloudAlibaba-Sentinel持久化到Nacos

前言 在前面我们已经将Sentinel配置的规则持久化到系统的文件中。本章节我们将Sentinel持久化到Nacos中; 传送门(Sentinel数据持久化到文件)https://blog.csdn.net/weixin_45876411/article/details/140742963 默认情况下 Sentinel 只能接收到 Nacos 推送的消息&#xff0c;但…

火情监测识别摄像机

火情监测识别摄像机 是一种用于监测和识别火灾风险的设备&#xff0c;通常用于森林、草原以及其他火灾易发区域。这种摄像机能够实时监测周围的环境&#xff0c;并使用图像识别技术来识别火灾的迹象。 这些摄像机通常配备红外热成像技术和视频分析算法&#xff0c;可以在白天和…

程序二义性举例

// 程序二义性.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 //#include <iostream> using namespace std; void f(int x) {cout << "---" << x << endl;} void f(int x,int y10) {cout << "" &l…

客流预测 | 基于Transformer下车站点客流推断研究(Matlab)

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基于Transformer的车站客流推断研究是指利用Transformer模型来预测车站的客流情况。Transformer是一种强大的深度学习模型&#xff0c;特别擅长处理序列数据。研究可以为城市交通管理提供重要决策支持&#xff0c;帮…

【系统分析师】-面向对象方法

目录 1、基本概念 2、UML 2.1、基本结构 2.1.1.构造块 2.1.1.1、事物 2.1.1.2、关系 2.1.1.3、图形 2.1.2.规则 2.1.3.公共机制 2.2、41视图 3、面向对象分析OOA 3.1、用例模型 3.2、分析模型 4、面向对象设计OOD 4.1、细分 4.2、设计原则 5、面向对象的程序设…

传统CV算法——基于harris检测算法实现角点检测

角点 角点是图像中的一个特征点&#xff0c;指的是两条边缘交叉的点&#xff0c;这样的点在图像中通常表示一个显著的几角。在计算机视觉和图像处理中&#xff0c;角点是重要的特征&#xff0c;因为它们通常是图像中信息丰富的区域&#xff0c;可以用于图像分析、对象识别、3D…

大模型(LLM)和知识库的基础介绍

文章目录 概要整体架构流程结合LLM与RAP的优势小结 概要 随着自然语言处理技术的发展&#xff0c;大型语言模型&#xff08;LLM&#xff09;已经成为了人工智能领域中的一个重要组成部分。这些模型通常具有数亿到数千亿个参数&#xff0c;能够理解和生成自然语言&#xff0c;从…

LabVIEW程序员错误排查思路

当LabVIEW程序员在开发过程中遇到难以解决的错误且网上搜不到答案时&#xff0c;需要采取系统性的方法进行排查和解决。这包括回顾代码逻辑、深入理解LabVIEW的底层机制、参考专业文献和求助社区等方式。下面将从多角度详细解读专业程序员在面对这种困境时的应对策略&#xff0…

网络安全等级保护:等级保护工作、分级保护工作、密码管理工作三者之间的关系

上次我整理了一篇文字叫《等级保护、等级保护测评、分级保护测评、密码保护测评之间的区别与联系》&#xff0c;后来发现这种措辞还是存在问题&#xff0c;今天在此重新做个探讨&#xff0c;同时进行更正。我们很多从事信息安全行业的人&#xff0c;交流时常常会提及“等保”“…

【淘宝采集项目经验分享】商品评论采集 |商品详情采集 |关键词搜索商品信息采集

商品评论采集 1、输入商品ID 2、筛选要抓取评论类型 3、填写要抓取的页数 4、立刻提交-启动测试 5、等爬虫结束后就可以到“爬取结果”里面下载数据 商品详情采集 1、输入商品ID 2、立刻提交-启动爬虫 3、等爬虫结束后就可以到“爬取结果”里面下载数据 taobao.item_…

数据结构排序方法总结

给定两个数组A,B&#xff0c;将A,B排序合并成一个数组&#xff0c;输出升序排列后的新数组。数组A,B中为整数&#xff0c;字母。 下面是代码&#xff1a; import java.util.Arrays;public class Solution15 {//冒泡排序public static void bubbleSort(String[] array) {int n…