【数据结构】:破译排序算法--数字世界的秩序密码(一)

文章目录

  • 一.排序算法概述
    • 1.定义和目的
    • 2.排序算法的分类
      • 2.1比较排序
      • 2.2非比较排序
  • 二.插入排序算法
    • 1.`InsertSort`直接插入排序
      • 1.1.插入排序原理
      • 1.2.插入排序过程
      • 1.3.代码实现
      • 1.4.复杂度和稳定性
    • 2.`ShellSort`希尔排序
      • 2.1.希尔排序原理
      • 2.2.希尔排序过程
      • 2.3.代码实现
      • 2.4.复杂度和稳定性
  • 三.选择排序算法
    • 1.`SelectionSort`简单选择排序
      • 1.1.选择排序原理
      • 1.2.选择排序过程
      • 1.3.代码实现
      • 1.4.复杂度和稳定性
    • 2.`HeapSort`堆排序
      • 2.1.堆排序原理
      • 2.2.堆排序过程
      • 2.3.代码实现
      • 2.4.复杂度和稳定性
  • 四.代码文件
    • 1.头文件`Sort.h`
    • 2.测试文件`test.c`
    • 3.测试结果
  • 总结

一.排序算法概述

排序算法是计算机科学中非常重要的一部分,它们的主要目的是将一个数据集合(如数组或列表)中的元素按照一定的顺序(如升序或降序)重新排列。排序算法的应用非常广泛,从简单的数据整理到复杂的数据库管理系统,都离不开排序算法的支持。

1.定义和目的

定义:排序算法是指将一组数据按照特定的顺序进行排列的算法。

目的:使得数据在逻辑上或物理上按照一定的顺序进行排列,以便于后续的数据查找、处理和分析等操作。

2.排序算法的分类

排序算法可以根据不同的标准进行分类,其中最常见的分类方式是基于比较非比较两种类型。

2.1比较排序

比较排序算法通过比较数据元素之间的大小关系来进行排序。这类算法的基本思想是:首先比较两个元素,如果它们的顺序错误就把它们交换过来;然后,对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对,这步做完后,最后的元素会是最大的数;接着,针对所有的元素(除了最后一个)重复以上的步骤,除了每次都比较到最后一对元素之外,每次比较的最后一对元素都是已经排好序的。这类排序算法的时间复杂度一般与数据的初始状态无关,主要取决于数据的规模。

2.2非比较排序

非比较排序算法则不依赖于元素之间的比较来进行排序。这类算法通常利用数据本身的特性(如元素的取值范围、数据的分布特性等)来设计排序算法。非比较排序算法的时间复杂度往往可以低于比较排序算法,但它们的适用范围相对较窄,且对数据的预处理要求较高。

二.插入排序算法

1.InsertSort直接插入排序

1.1.插入排序原理

  • 插入排序的基本思想是将一个记录插入到已将排好序的有序表中,从而得到一个新的,记录数增加一的有序表。

  • 在整个排序的过程中,始终维持着已将排好序的记录段,随着排序的过程的进行,不断增加这个有序段的长度,知道最后全部待排序的记录被插入到有序段中为止。

1.2.插入排序过程

  1. 初始状态将第一个元素视为已排序序列,剩下的元素视为未排序序列。

  2. 选取元素:从未排序序列中取出第一个元素,记为当前元素。

  3. 比较与移动

    • 将当前元素与已排序序列最后一个元素进行比较。
    • 如果已排序序列最后一个元素小于当前元素,则不需要移动,直接将当前元素插入到已排序序列最后。
    • 如果已排序序列最后一个元素大于当前元素,将已排序序列最后一个元素后移一位,然后继续比较当前元素与已排序序列最后一个元素
    • 重复上述步骤,直到找到当前元素在已排序序列中的正确位置并将其插入。
  4. 重复操作:从未排序序列中取出下一个元素,重复步骤2和3,直到未排序序列为空。

    在这里插入图片描述

1.3.代码实现

void InsertSort(int*a,int n){for(int i=1;i<n;i++){int end=i-1;int tmp=a[i];while(end>=0){if(a[end]>tmp){a[end+1]=a[end];end--;}else{break;}}a[end+1]=tmp;}
}

1.4.复杂度和稳定性

  • 时间复杂度:平均和最坏情况都是O(n^2)(当输入数组是逆序时,就是最坏情况),最好情况是O(n)(当输入数组是顺序时,就是最好情况)。
  • 空间复杂度:O(1),因为它是一种in-place排序算法。
  • 稳定性:插入排序的稳定性是稳定,小的往前,大的不动。

2.ShellSort希尔排序

2.1.希尔排序原理

希尔排序是插入排序的一种更高效的改进版本,也称为缩小增量排序。希尔排序的基本思想是将待排序的数组元素按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量的逐渐减少,每组包含的元素越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

2.2.希尔排序过程

  1. 选择初始增量:选择一个初始的增量gap(步长),这个增量的选择对希尔排序的性能有很大影响。gap越大,大的数越快跳到后面,小的数越快跳到前面,常用的增量选择方式有希尔原始增量序列(N/2, N/4, …, 1)、Hibbard增量序列、Knuth增量序列、Sedgewick增量序列等。

  2. 分组与排序:根据当前的增量gap,将数组分为若干个子序列,并对每个子序列进行预排序。

  3. 减少增量:将增量gap减少(通常减半),然后重复步骤2,直到增量gap为1,也就是直接插入排序

  4. 最终排序:当增量gap为1时,整个数组被视为一组,进行最后一次直接插入排序,得到最终的有序序列。

    在这里插入图片描述

2.3.代码实现

void ShellSort(int*a,int n){int gap=n;while(gap>1){gap/=2;for(int i=0;i<n-gap;i++){int end=i;tmp=a[i+gap];while(end>=0){if(a[end]>tmp){a[end+gap]=a[end];end-=gap;}else{break;}}a[end+gap]=tmp;}}
}

2.4.复杂度和稳定性

  • 时间复杂度:希尔排序的时间复杂度依赖于增量gap的选择。在最坏情况下,时间复杂度为O(n^2) ,但在平均情况下,时间复杂度可以降到O(nlogn)到O(n^1.5)之间 。因为希尔排序时间复杂度较为复杂,所以直接记结论就可以,希尔排序时间复杂度约为O(n^1.3)。
  • 空间复杂度:希尔排序是原地排序算法,空间复杂度为O(1)。
  • 稳定性:希尔排序的稳定性是不稳定比如相同的数据可能会被分配到不同的组预排序,从而打乱相同数据的原本顺序。

三.选择排序算法

1.SelectionSort简单选择排序

1.1.选择排序原理

选择排序(Selection Sort)是一种简单直观的排序算法。它的基本思想是:第1次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的元素中寻找最小(或最大)的元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素排完。

1.2.选择排序过程

1.设置下标:整体循环条件是左端下标(left)小于右端下标(right),每次循环时都将最大值的下标(max)和最小值的下标(min)先设置为左端下标(left)。

2.查找下标:从左端下标(left)的下一个开始查找,找到最大值和最小值的下标。

3.交换:将最小值和左端(left)的值交换,最大值和右端(right)的值交换,如果最大值恰好在左端位置时,在最小值和左端(left)的值交换后,要先交换最大值和最小值的下标。才能再进行最大值和右端(right)的值交换

4.重复操作:左右交换后,左端下标(left)加一,右端下标(right)减一,然后循环进行过程1,2,3。

在这里插入图片描述

1.3.代码实现

//交换函数
void Swap(int*a,int*b){int t=*a;*a=*b;*b=t;
}
void SelectSort(int*a,int n){//设置左端下标left,右端下标rightint left=0,right=n-1;while(left<right){//每次循环时设置最大值和最小值的下标从left开始int max=left,min=left;//循环遍历找到max,min的下标for(int i=left+1;i<n;i++){if(a[i]>a[max]){max=i;}if(a[i]<a[min]){min=i;}}//先将最左端的值和最小值交换Swap(&a[left],&a[min]);//当最大值下标等于左端下标时,max下标要变为min的下标if(left==max){max=min;}//再将最右端的值和最小端的值交换Swap(&a[right],&a[max]);//左端下标加一,右端下标减一left++;right--;}
}

1.4.复杂度和稳定性

  • 时间复杂度 : 选择排序的时间复杂度为O(n^2),无论最好情况、最坏情况还是平均情况都如此。这是因为,即使输入数组已经是排序好的,选择排序仍然需要遍历数组来找到最小(或最大)的元素。
  • 空间复杂度:选择排序的空间复杂度为O(1),因为它只需要常数个额外的存储空间来存储临时变量。
  • 稳定性:选择排序的稳定性是不稳定比如数组【2,2,1,5,4】,第一个2和1交换后会改变原本数组中2,2,的相对位置,所以是不稳定的。

2.HeapSort堆排序

2.1.堆排序原理

堆排序(HeapSort)是一种基于比较的排序算法,其原理是利用堆这种数据结构所设计。堆是一个近似完全二叉树的结构,并同时满足堆的性质:即每个节点总是大于或小于子节点(堆的详细讲解在我之前的文章中有讲解到,如果对堆有不了解的可以看我之前的文章)。

2.2.堆排序过程

堆排序的过程主要分为两个过程:

  • 构建堆:将待排序的序列构建成最大堆(升序),此时,堆顶的根节点就是整个序列的最大值。(如果构建的是最小堆(降序),堆顶的根节点就是整个序列的最小值。)
  • 堆排序:将堆顶元素最大值(或最小值)与堆的末尾元素交换,此时堆的末尾就是最大值(或最小值),然后将剩下的n-1个元素重新构建成堆,这样就会得到n个元素的次大值(或次小值),如此反复进行最后就会得到一个有序序列。

在这里插入图片描述

2.3.代码实现

//交换
void Swap(int*a,int*b){int t=*a;*a=*b;*b=t;
}
//向下调整
void AdjustDown(int*a,int n,int i){//参数i作为父节点,找到子节点int parent=i;int child=parent*2+1;while(child<n){//从左右子节点中选出较大的节点if(child+1<n&&a[child+1]>a[child]){child++;}//判断父子节点是否需要交换if(a[child]>a[parent]){Swap(&a[child],&a[parent]);}parent=child;child=parent*2;}
}void HeapSort(int*a,int n){//先将给定的一个数组用向下调整建堆,将数组调整成堆的形式for(int i=(n-1-1)/2;i>=0;i++){AdjustDown(a,n,i);}//每次将堆顶的元素和最后一个元素交换,从新建堆int end=n-1;while(end>=0){Swap(&a[0],&a[end]);AdjustDown(a,end,0);end--;}
}

2.4.复杂度和稳定性

  • 时间复杂度:堆排序的平均时间复杂度和最坏时间复杂度均为O(n*log n),(详细可以看我之前的文章)
  • 空间复杂度:由于堆排序在构建堆和调整堆的过程中,都需要进行元素的比较和移动因此堆排序的空间复杂的是O(1),是一种原地排序算法。
  • 稳定性:堆排序的稳定性是不稳定

四.代码文件

这里附上整个代码文件:

  • 头文件Sort.h
  • 测试文件test.c
  • 接口函数实现文件Sort.c(文件内容就是每个代码实现)

1.头文件Sort.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>//遍历打印
void PrintArray(int* a, int n);
//插入排序
void InsertSort(int* a, int n);
//希尔排序
void ShellSort(int* a, int n);
//选择排序
void SelectSort(int* a, int n);
//交换
void Swap(int* a, int* b);
//向下调整
void AdjustDown(int* a, int n, int i);
//堆排序
void HeapSort(int* a, int n);

2.测试文件test.c

#include"sort.h"
//插入排序测试
void Inserttest() {int a[ ] = { 7,3,5,4,6};int n = (sizeof(a) / sizeof(int));InsertSort(a, n);printf("插入排序:\n");PrintArray(a, n);
}
//希尔排序测试
void Shelltest() {int a[ ] = {12,5,17,9,14,13,2,4,19};int n = (sizeof(a) / sizeof(int));ShellSort(a, n);printf("希尔排序:\n");PrintArray(a, n);
}
//选择排序测试
void Selecttest() {int a[ ] = { 3,6,4,2,11,10,5};int n = (sizeof(a) / sizeof(int));SelectSort(a, n);printf("选择排序:\n");PrintArray(a, n);
}
//堆排序测试
void Heaptest() {int a[ ] = { 3,12,7,3,1,5,24,9,8,10,2,4 };int n = (sizeof(a) / sizeof(int));HeapSort(a, n);printf("堆排序:\n");PrintArray(a, n);
}int main(){Inserttest();Shelltest();Selecttest();Heaptest();return 0;
}

3.测试结果

在这里插入图片描述

总结

本篇文章主要讲述了插入排序,希尔排序,选择排序和堆排序,剩下的冒泡排序,快速排序,归并排序和计数排序我将会放在下一篇文章中。
以上就是关于排序部分的讲解,如果哪里有错的话,可以在评论区指正,也欢迎大家一起讨论学习,如果对你的学习有帮助的话,点点赞关注支持一下吧!!!

在这里插入图片描述

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

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

相关文章

【.net core使用minio大文件分片上传】.net core使用minio大文件分片上传以及断点续传、秒传思路

版本&#xff1a;.net core 7 需求&#xff1a;net限制了上传的大小&#xff0c;只能上传25M上下的文件&#xff0c;如果上传一个八十多兆的文件&#xff0c;swagger接口报错&#xff0c;如果前端调用上传接口&#xff0c;会报CORS跨域错误&#xff0c;这篇文章介绍怎么使用分片…

使用CSS和HTML实现3D图片环绕效果

使用CSS和HTML实现3D图片环绕效果 在本篇博客中&#xff0c;将介绍如何使用HTML和CSS实现一个3D图片环绕效果。这个效果不仅具有视觉吸引力&#xff0c;而且具有高度的互动性&#xff0c;鼠标悬停时动画会暂停。接下来将一步步讲解这个效果的实现过程。 1. 效果 2. 页面结构与…

【华为HCIP实战课程十一】OSPF网络NBMA网络解决方案,网络工程师

上节我们讲解了DR DBR 选举,每台设备可以学到全网路由,但是通信是有问题的 DR BDR的选举是基于接口的,而不是基于路由器的 一、OSPF路由通信问题 R5虽然可以学到全网的OSPF路由,但是R5无法ping通44.1.1.1 原因是R5到达R4 lo0的下一跳是10.1.1.4, 而R5和R4直连无法ping通…

数码准备记录

1.数据结构 常见的数据结构包括数组、链表、栈、队列、树&#xff08;如二叉树、B树、B树&#xff09;、图等 2.队列和栈的区别 队列是一种先入先出的数据结构&#xff0c;即最先加入的元素被最先移除&#xff1b; 栈是一种后进后出的数据结构&#xff0c;即最后加入的元素…

linux tar 打包文件去掉文件所在路径

一、准备目录 /root/tmp/images /root/tmp/images2 执行命令打包目录/root/tmp/images 到 /root/tmp/images.tar.gz 再解压到/root/tmp/images2 cd /root/tmp/images && tar -cvzf images.tar.gz * && mv images.tar.gz /root/tmp/ tar -C /root/tmp/image…

JDK17常用新特性

目前国内大部分开发人员都是在使用jdk8&#xff0c;甚至是jdk6&#xff0c;但是随着jdk的更新迭代&#xff0c;jdk8我觉得可能就会慢慢的淡出舞台&#xff0c;随着目前主流框架最新版推出明确说明了不再支持jdk8&#xff0c;也促使我不得不抓紧学习了解一波jdk17的新特性&#…

多线程-初阶(2)BlockingQueueThreadPoolExecutor

学习目标&#xff1a; 熟悉wait和notify的线程休眠和启动 熟悉多线程的基本案例 1.单例模式的两种设置模式:懒汉模式和饿汉模式 2.阻塞队列(生产者消费者模型) 3.线程池 4.定时器 1.wait和notify 由于线程之间是抢占式执⾏的, 因此线程之间执⾏的先后顺序难以预知. 但是…

【消息队列】Kafka从入门到面试学习总结

国科大学习生活&#xff08;期末复习资料、课程大作业解析、大厂实习经验心得等&#xff09;: 文章专栏&#xff08;点击跳转&#xff09; 大数据开发学习文档&#xff08;分布式文件系统的实现&#xff0c;大数据生态圈学习文档等&#xff09;: 文章专栏&#xff08;点击跳转&…

人工智能的核心技术之机器学习

大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 人工智能&#xff08;AI&#xff09;核心技…

使用DataX同步hive数据到MySQL

目录 1、组件环境 2、安装datax 2.1、下载datax并解压 3、安装datax-web 3.0、下载datax-web的源码&#xff0c;进行编译 3.1、在MySQL中创建datax-web元数据 3.2、安装data-web 3.2.1执行install.sh命令解压部署 3.2.1、手动修改 datax-admin配置文件 3.2.2、手动修改…

「Ubuntu」文件权限说明(drwxr-xr-x)

我们在使用Ubuntu 查看文件信息时&#xff0c;常常使用 ll 命令查看&#xff0c;但是输出的详细信息有些复杂&#xff0c;特别是 类似与 drwxr-xr-x 的字符串&#xff0c;在此进行详细解释下 属主&#xff1a;所属用户 属组&#xff1a;文件所属组别 drwxr-xr-x 7 apps root 4…

Pytorch基础:设置随机种子

相关阅读 Pytorch基础https://blog.csdn.net/weixin_45791458/category_12457644.html?spm1001.2014.3001.5482 有时候&#xff0c;如果需要代码在多个运行中具有可重复性&#xff0c;可以通过以下方式来设置随机种子&#xff1a; import torch import numpy as np import r…

【亲测可行】最新ubuntu搭建rknn-toolkit2

文章目录 🌕结构图(ONNX->RKNN)🌕下载rknn-toolkit2🌕搭建环境🌙配置镜像源🌙conda搭建python3.8版本的虚拟环境🌙进入packages目录安装依赖库🌕测试安装是否成功🌕其它🌙rknn-toolkit2🌙rknn_model_zoo🌙关于部署的博客发布本文的时间为2024.10.13…

【进阶OpenCV】 (11)--DNN板块--实现风格迁移

文章目录 DNN板块一、DNN特点二、DNN函数流程三、实现风格迁移1. 图像预处理2. 加载星空模型3. 输出处理 总结 DNN板块 DNN模块是 OpenCV 中专门用来实现 DNN(Deep Neural Networks,深度神经网络) 模块的相关功能&#xff0c;其作用是载入别的深度学习框架(如 TensorFlow、Caf…

【微信小程序_11_全局配置】

摘要:本文介绍了微信小程序全局配置文件 app.json 中的常用配置项,重点阐述了 window 节点的各项配置,包括导航栏标题文字、背景色、标题颜色,窗口背景色、下拉刷新样式以及上拉触底距离等。通过这些配置可实现小程序窗口外观的个性化设置,提升用户体验。 微信小程序_11_全…

如何成为 Rust 核心贡献者?Rust 开发的核​​心是什么?Rust 重要技术专家揭秘

10 月 17 - 18日&#xff0c;由 GOSIM 开源创新汇主办、CSDN 承办的 GOSIM CHINA 2024 将在北京盛大启幕。作为 GOSIM 开源年度大会的第三届盛会&#xff0c;本次活动邀请了 60 多位国际开源专家&#xff0c;汇聚了来自全球百余家顶尖科技企业、知名高校及开源社区的技术大咖、…

回溯法与迭代法详解:如何从手机数字键盘生成字母组合

在这篇文章中&#xff0c;我们将详细介绍如何基于手机数字键盘的映射&#xff0c;给定一个仅包含数字 2-9 的字符串&#xff0c;输出它能够表示的所有字母组合。这是一个经典的回溯算法问题&#xff0c;适合初学者理解和掌握。 问题描述 给定一个数字字符串&#xff0c;比如 …

python基础路径的迁移

本人未安装anaconda或pycharm等&#xff0c;仅安装了某个python环境&#xff0c;因此以下方法仅针对基础python环境的迁移&#xff0c;不确保其他软件或插件正常运行 第一步将原python路径的整个文件夹剪切到新的路径下 第二步修改系统环境变量&#xff0c;将原来的python路径…

php 生成随机数

记录&#xff1a;随机数抽奖 要求&#xff1a;每次生成3个 1 - 10 之间可重复&#xff08;或不可重复&#xff09;的随机数&#xff0c;10次为一轮&#xff0c;每轮要求数字5出现6次、数字4出现3次、…。 提炼需求&#xff1a; 1&#xff0c;可设置最小数、最大数、每次抽奖生…

鸿蒙--商品列表

这里主要利用的是 List 组件 相关概念 Scroll:可滚动的容器组件,当子组件的布局尺寸超过父组件的视口时,内容可以滚动。List:列表包