数据结构—内部排序(上)

文章目录

  • 8.内部排序(上)
    • (1).排序基础
      • #1.为什么是内部排序
      • #2.排序的稳定性
    • (2).冒泡排序
      • #1.算法思想
      • #2.代码实现
      • #3.稳定性与时间复杂度分析
    • (3).选择排序
      • #1.算法思想
      • #2.代码实现
      • #3.稳定性与时间复杂度分析
    • (4).插入排序
      • #1.算法思想
      • #2.代码实现
      • #3.稳定性与时间复杂度分析
    • (5).希尔排序
      • #1.算法思想
      • #2.代码实现
      • #3.稳定性和时间复杂度分析
    • 小结

8.内部排序(上)

  所以其实学会对一组数据进行排序,是我们很自然的想法,比如我们在玩扑克牌的时候随机摸了一组牌,为了之后打起来方便,你可能也会按照花色和数字进行排序,所以,让我们来了解一下排序吧!

(1).排序基础

#1.为什么是内部排序

  与内部排序相对的,就是外部排序,在数据量极其庞大的情况下,我们可能无法一次性将待排序的数据全部载入内存再排序,而这种涉及到内存与外存数据交换的排序方式就称为外部排序,与之相对的就是内部排序,我们可以很简单的一次性把所有数据载入内存,用各种方式完成排序。

  外部排序的流程比较复杂,因此基于数据结构这门课的这系列博客当中,我们会简要介绍内部排序的基本内容。

#2.排序的稳定性

  排序算法是具有稳定性的说法的,在待排序的数据当中,基于排序规则相同的一系列数据如果能在排序完成后保持原有的顺序,则称这种排序算法是稳定的
  例如5, 1, 2(1), 4(1), 4(2), 2(2), 4(3),稳定排序的结果应当是:1,2(1), 2(2), 4(1), 4(2), 4(3), 5

(2).冒泡排序

#1.算法思想

  冒泡排序是相当自然的排序方法,假设从小到大排序,我们从左往右,依次比较相邻的元素,如果满足左边小于等于右边,就继续比较下面两个元素,如果顺序错误,则交换两个元素,继续交换

#2.代码实现

  如此继续下去可以保证每轮都能找出一个最大值,并且将它放在最后,这样的过程就好像一个个泡泡从水底逐渐冒到了水面上,故称为冒泡排序,它的代码实现如下:

#include <iostream>
#include <vector>
using namespace std;void bubble_sort(vector<int>& v)
{bool isSort{ false };for (int i = v.size() - 1; i >= 0; i--) {for (int j = 0; j < i; j++) {if (v[j] > v[j + 1]) {int tmp{ v[j + 1] };v[j + 1] = v[j];v[j] = tmp;isSort = true;}}if (!isSort) break;}
}int main()
{vector<int> v{ 3, 2, 3, 5, 6, 7, 8, 9, 1, 23 };bubble_sort(v);for (auto& i : v) {cout << i << " ";}cout << endl;return 0;
}

#3.稳定性与时间复杂度分析

  我们每次将冒泡的上界减一,然后每次再找到位置错误的进行交换,一直这样循环下去即可。接下来分析一下冒泡排序的时间复杂度,我们有两重循环,可以得到:
T ( n ) = ∑ k = 1 n ( n − k ) = n ( n − 1 ) 2 ⇒ O ( T ( n ) ) = O ( n 2 ) T(n) = \sum_{k=1}^n (n-k) = \frac{n(n-1)}{2}\Rightarrow O(T(n))=O(n^2) T(n)=k=1n(nk)=2n(n1)O(T(n))=O(n2)
  所以冒泡排序是比较基本的 O ( n 2 ) O(n^2) O(n2)排序算法,然后是稳定性,其实这个好说,因为在冒泡排序中我们只涉及到前后两个顺序错误元素的交换,因此相同的元素在这个过程中是不会被交换的,所以冒泡排序是一种稳定的排序方式

(3).选择排序

#1.算法思想

  选择排序则要更接近我们自己尝试排序的过程,比如3, 2, 3, 5, 6, 7, 8, 9, 1, 23这个序列,我们首先找到最小值1,放到最前面:1, 3, 2, 3, 5, 6, 7, 8, 9, 23,然后从1后取第二个最小值放到第二个位置:1, 2, 3, 3, 5, 6, 7, 8, 9, 23,然后就这么做下去吧!每次找出最小值或者最大值,放到上一次放的下一个位置,就可以完成整个排序流程了,这就是插入排序。

#2.代码实现

  每次选择一个最小或最大的值出来,放到头或尾去,因此这个算法称为选择排序。

#include <iostream>
#include <vector>
using namespace std;void selection_sort(vector<int>& v)
{for (int i = 0; i < v.size() - 1; i++) {int min_idx{ i };for (int j = i + 1; j < v.size(); j++) {if (v[min_idx] > v[j]) {min_idx = j;}}int tmp{ v[i] };v[i] = v[min_idx];v[min_idx] = tmp;}
}int main()
{vector<int> v{ 3, 2, 3, 5, 6, 7, 8, 9, 1, 23 };selection_sort(v);for (auto& i : v) {cout << i << " ";}cout << endl;return 0;
}

  这段代码主要也就做了两件事:找后续值的最小值以及放到对应的位置上去

#3.稳定性与时间复杂度分析

  还是先看看时间复杂度吧,这里就不推了,其实还是和冒泡排序相似的过程,选择排序的时间复杂度仍然是 O ( n 2 ) O(n^2) O(n2),所以我们想要突破 O ( n 2 ) O(n^2) O(n2)的时间复杂度,好像非常困难啊。

  然后是稳定性,选择排序实际上是一种不稳定的排序方式,比如我们前面写的代码,对于这个序列:1, 2, 3, 2, 1,当i走到1的时候,2会与后面的1进行一次交换,而这样做之后就破坏了原本两个2的顺序,这样就导致选择排序变得不稳定了起来,比如:
p16

(4).插入排序

#1.算法思想

  插入排序在我们玩扑克牌的时候比较常用,比如我们拿到了一副牌:A,7,4,2,Q,9,J,那我们可能会这么排,首先A不动,看到7,也不动,再到4,插到A和7之间,再把2插入A和4之间,就这么做下去,直到变成A,2,4,7,9,J,Q这样的顺序,这就是插入排序,我们依次向后遍历,然后找到对应元素在前面已经有序的序列中的位置,插入进去,这就是插入排序的基本流程

#2.代码实现

  我们这里把找到合适的位置和移动合在一起,可以减少一次遍历的开销

#include <iostream>
#include <vector>
using namespace std;void insertion_sort(vector<int>& v)
{for (int i = 1; i < v.size(); i++) {int tmp{ v[i] };int j = i - 1;for (; j >= 0 && tmp < v[j]; j--) {v[j + 1] = v[j];}v[j + 1] = tmp;}
}int main()
{vector<int> v{ 1, 2, 3, 2, 1 };insertion_sort(v);for (auto& i : v) {cout << i << " ";}cout << endl;return 0;
}

#3.稳定性与时间复杂度分析

  插入排序的复杂度同样为 O ( n 2 ) O(n^2) O(n2),不过插入排序对于基本有序的序列,插入排序的移动和查找操作次数非常少,所以之后在设计你自己的排序方式的时候,可以尝试在基本有序的情况下使用插入排序优化,而在比较混乱的情况下采取更快的排序方式

  稳定性其实很好分析,我们的排序过程中不存在直接交换两个点的过程,只是依次向左交换,因此插入排序可以保证稳定性。

  还有一个点需要注意的点,插入排序对于链式存储也是比较容易的,因为不涉及到点的随机访问。对了,对于数组的实现,我们或许还可以使用二分查找的方式更快地找到插入的位置,不过时间复杂度是不会变的哦

(5).希尔排序

#1.算法思想

  希尔排序是一种基于插入排序的修改法则,我们在插入排序的过程中每次往前移动一个位置,而如果能一次移动更多位置,或许排序的速度就能被优化了。

  因此希尔排序(递减增量排序)就出现了,我们给出 d 0 , d 1 , d 2 , . . . , d t − 1 d_0,d_1,d_2,...,d_{t-1} d0,d1,d2,...,dt1这么一系列严格递减的正整数增量,且 d t − 1 = 1 d_{t-1}=1 dt1=1
,每次排序的时候,对整个序列按照增量为 d i d_i di进行分组,然后对不同的分组分别进行排序,直到最后再用增量为1的序列对所有数据进行一次排序。

  需要注意的是,我们可以保证这么排序一定至少不会让时间复杂度变高,因为插入排序本身对于基本有序的数据的排序时间复杂度就会更低。

#2.代码实现

  基本上,我们只需要在基本的插入排序前面加一层对于递减增减的序列就好了,然后把对应的j-1改成j-delta,就好了:

#include <iostream>
#include <vector>
using namespace std;void shell_sort(vector<int>& v)
{vector<int> d{ 7, 5, 3, 1 };for (int delta = 0; delta < d.size(); delta++) {int h = d[delta];for (int i = h; i < v.size(); i++) {int tmp{ v[i] };int k{ i - h };for (; k >= 0 && tmp < v[k]; k -= h) {v[k + h] = v[k];}v[k + h] = tmp;}}
}int main()
{vector<int> v{ 1, 2, 3, 2, 1, 2, 3, 2, 1 };shell_sort(v);for (auto& i : v) {cout << i << " ";}cout << endl;return 0;
}

#3.稳定性和时间复杂度分析

  希尔排序的时间复杂度很难分析,它的时间复杂度基本基于你的增量序列选择,这里要注意,增量序列要避免出现因子,比如9和3同时出现就会多一次没有必要的排序。

  Knuth在1969年推荐了这样一个序列: d i + 1 = 3 d i + 1 d_{i+1}=3d_i+1 di+1=3di+1,经过分析,比较的次数不超过 O ( n 3 2 ) O(n^{\frac{3}{2}}) O(n23)我们终于突破了 O ( n 2 ) O(n^2) O(n2)!

小结

  最近实在是太忙,今天只能暂时先把内部排序的上半部分发出来了,下半部分我们会讲讲归并排序、快速排序和基数排序的内容。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

advanced-css: No.1

本套教程学习来自视频&#xff1a;https://www.bilibili.com/video/BV1n94y1o7yS/?p7&spm_id_frompageDriver&vd_sourceb79be8283df9418cb45941cc0bd583c6 案例 实现效果图 代码 HTML: <!DOCTYPE html> <html lang"en"><head><meta c…

Docker - 安装

Docker安装 Docker的基本组成 镜像&#xff08;image&#xff09;: ​ Docker镜像就好比是一个模板&#xff0c;可以通过这个模板来创建容器服务&#xff0c;tomcat镜像 -> run -> tomcat01容器&#xff08;提供服务器&#xff09;&#xff0c;通过这个镜像可以创建多个…

Git基本概念和使用方式

Git 是一种版本控制系统&#xff0c;用于管理文件版本的变化。以下是其基本概念和使用方式&#xff1a; 仓库&#xff08;repository&#xff09;&#xff1a;Git 存储代码的地方&#xff0c;可以理解为一个项目的文件夹。提交&#xff08;commit&#xff09;&#xff1a;Git …

联邦学习的梯度重构

联邦学习中的梯度出现挑战&#xff1a; 暴露原始训练数据的某些属性 利用生成对抗网络生成与私有训练图像类似的图片 尽管许多研究已经证实从梯度中重构原始数据的可能性&#xff0c;这些研究通常基于一个前提假设&#xff0c;即用户上传的梯度是全梯度。 联邦学习系统更倾…

栈和队列:栈

栈的概念&#xff1a; 栈&#xff1a; 一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。 栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。…

Antd G6实现自定义工具栏

在使用g6实现知识图谱可视化中&#xff0c;产品经理提出了有关图谱操作的不少功能&#xff0c;需要放置在工具栏中&#xff0c;其中有些功能不在g6自带的功能里&#xff0c;且工具栏样式、交互效果也和官方自定义工具栏不同。那我们怎么去实现呢&#xff1f; g6官方的工具栏案例…

excel如何加密(excel加密的三种方法)

Excel是一款广泛使用的办公软件&#xff0c;有时候我们需要对一些重要的Excel文件进行加密&#xff0c;以保证文件的安全性。下面将介绍3种常用的Excel加密方法。 方法一&#xff1a;通过路径文件-另存为-工具-常规选项-设置打开或修改权限密码&#xff08;密码只可以使数字、字…

从0开始python学习-34.pytest常用插件

目录 1. pytest-html&#xff1a;生成HTML测试报告 2.pytest-xdist&#xff1a;并发执行用例 3. pytest-order&#xff1a;自定义用例的执行顺序 4. pytest-rerunfailures&#xff1a;用例失败时自动重试 5. pytest-result-log:用例执行结果记录到日志文件 1. pytest-html…

Nacos热更新

Nacos热更新 相比其他注册中心&#xff0c;Nacos的优势之一在于热更新。 热更新&#xff0c;就是不需要重启服务&#xff0c;就能够更新配置。 nacos配置中心 首先&#xff0c;需要搭建 Nacos&#xff0c;详情见&#xff1a; https://www.cnblogs.com/expiator/p/17392549.h…

Docker本地部署Drupal并实现公网访问

文章目录 前言1. Docker安装Drupal2. 本地局域网访问3 . Linux 安装cpolar4. 配置Drupal公网访问地址5. 公网远程访问Drupal6. 固定Drupal 公网地址 前言 Dupal是一个强大的CMS&#xff0c;适用于各种不同的网站项目&#xff0c;从小型个人博客到大型企业级门户网站。它的学习…

数据管理系统-week1-文件系统、数据库和数据库管理系统

文章目录 前言一、 文件系统文件系统的限制 二、 数据库系统三、 数据库管理系统参考文献 前言 一、 文件系统 对于更高级的数据处理应用程序来说&#xff0c;基于数据块的持久存储逻辑模型过于简单数据块序列被划分为称为文件的数据块的可变子序列&#xff0c;与文件相关的名…

键盘打字盲打练习系列之认识键盘——0

一.欢迎来到我的酒馆 盲打&#xff0c;yyds&#xff01; 目录 一.欢迎来到我的酒馆二.键盘规格三.键盘分区 二.键盘规格 经常看视频&#xff0c;看到别人在键盘上一通干净利索的操作&#xff0c;就打出想要的文字。心里突然来一句&#xff1a;卧槽&#xff0c;打字贼快啊&#…

pytest全局变量的使用

这里重新阐述下PageObject设计模式&#xff1a; PageObject设计模式是selenium自动化最成熟&#xff0c;最受欢迎的一种模式&#xff0c;这里用pytest同样适用 这里直接提供代码&#xff1a; 全局变量 conftest.py """ conftest.py 全局变量&#xff0c;主要实…

AI:76-基于机器学习的智能城市交通管理

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌在这个漫长的过程,中途遇到了不少问题,但是…

asp.net外卖网站系统VS开发mysql数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net外卖网站系统 是一套完善的web设计管理系统&#xff0c;系统采用mvc模式&#xff08;BLLDALENTITY&#xff09;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为mysql&#xff0c;使用c#语…

【Unity之UI编程】玩法面板的实现

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;UI_…

Spring Cloud和Kubernetes + Spring Boot 用哪个?

Spring Cloud和Kubernetes Spring Boot都是用于构建微服务架构的解决方案&#xff0c;它们各有优势和不足&#xff0c;选择哪个更好取决于你的具体需求和上下文。 Spring Cloud是一个基于Spring Boot的微服务开发框架&#xff0c;它提供了一套完整的微服务解决方案&#xff0…

OpenMMlab导出yolov3的onnx模型并推理

手动导出 直接使用脚本 import torch from mmdet.apis import init_detector, inference_detectorconfig_file ./configs/yolo/yolov3_mobilenetv2_8xb24-ms-416-300e_coco.py checkpoint_file yolov3_mobilenetv2_mstrain-416_300e_coco_20210718_010823-f68a07b3.pth mod…

Django(复习篇)

项目创建 1. 虚拟环境 python -m venv my_env ​ cd my_env activate/deactivate ​ pip install django ​2. 项目和app创建 cd mypros django-admin startproject Pro1 django-admin startapp app1 ​3. settings配置INSTALLED_APPS【app1"】TEMPLATES【 DIRS: [os.pat…

JavaEE初阶学习:Linux 基本使用和 web 程序部署

1.Linux的基本认识 Linux 是一个操作系统.(搞管理的系统) 和Windows都是同类产品~~ Linux 实际的场景: 1.服务器 2.嵌入式设备 3.移动端(手机)Android 其实就是Linux 1991年,还在读大学的 芬兰人 Linus Benedict Torvalds,搞了一个Linux 这样的系统0.01版,正式发布了~ 后…