排序(详解)上

简介: 排序(详解)

排序的概念


排序:将杂乱无章的数据元素,通过一定的方法按关键字顺序排列的过程叫做排序


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

外部排序:由于数据太多不能全部放在内存中,需要借助外存的排序


常见的排序算法


比较排序

插入排序:直接插入排序,希尔排序

选择排序:直接选择排序,堆排序

交换排序:冒泡排序,快速排序

归并排序:归并排序


非比较排序


计数排序


直接插入排序


思路:

直接插入排序是指在待排序的元素中,假设前面n-1(其中n>=2)个数已经是排好顺序的,现将第n个数插到前面已经排好的序列中,然后找到合适自己的位置,使得插入第n个数的这个序列也是排好顺序的


算法实现


void Insertsort(int* a, int n)
{
  int i = 0;
  for (i = 0; i < n - 1; i++)
  {
     //[0,end],在end+1位置上插入一个数,使[0,end+1]有序
  int end = i;
  int tmp = a[end + 1];
  while (end >= 0)
  {
    if (tmp < a[end])
    {
    a[end + 1] = a[end];
    end--;
    }
    else
    {
    break;
    }
  }
  //跳出循环有两种可能
  //1.end已经越界,此时end==-1
  //2.找到比tmp小的数据
  a[end + 1] = tmp;
  }
}


图形展示


4ce0c58215c70024841a835438247751_d33a1b82f373473fa9810a9369ee6485.png


运行结果


493be3392192aff922fb1d98b4669279_a0f90c866ec248a6827dd412e8ad678a.png


直接插入排序的特点


元素集合越接近有序,插入排序的时间效率便越高

时间复杂度:O(N^2)

空间复杂度:O(1)

稳定性:稳定


希尔排序(缩小增量排序)


思路:

先选定一个整数,把待排序的数据按一定距离分成若干小组,对每一组内的数据进行排序;然后逐渐减小距离,重复上面的操作,直到距离为1所有数据被分到一组,结束排序


图形展示


63690826ea9c4dd735d3c442e5113a8e_700817dbb2df45028397e10707e29d7d.png


算法实现


void Shellsort(int* a, int n)
{
  int gap = n;
  while (gap > 0)
  {
  gap /= 2;
  int i = 0;
  //gap组数据依次多组并排
  for (i = 0; i < n - gap; i++)
  {
    int end = i;
    //[0,end],在end+gap位置上插入一个数据使[0,end+gap]有序
    int tmp = a[end + gap];
    while (end >= 0)
    {
    if (a[end] > tmp)
    {
      a[end + gap] = a[end];
      end -= gap;
    }
    else
    {
      break;
    }
    }
    a[end + gap] = tmp;
  }
  }
}


运行结果


2afa9f21b533198945c93df3b261b400_4486046c3e854d968f9925fd94db6b6c.png


希尔排序的特点


希尔排序是对插入排序的优化

当gap>1是称为预排序,目的便是使数组接近有序;gap越大,大的数据可以越快跳到后面,小的数据可以越快跳到前面;gap越小,数据跳的越慢,但也越接近有序;当gap==1时,数组已经接近有序,排序就更加的快

由于gap的取值没有统一的规定,便导致时间复杂度不易计算

稳定性:不稳定


选择排序


思路:

每次从待排序的数据中选出最小的和最大的数据,若这两个数据不是这组数据的第一个,最后一个数据,则将这两个数据与第一个,最后一个数据进行交换;然后再从剩余的数据中重复此操作,直到排完所有数据


8b4ece75467bccf9687fd7554fd10418_31feacfffa334fff82a69946f07a7dbf.png


算法实现


void Swap(int* p1, int* p2)
{
  int tmp = *p1;
  *p1 = *p2;
  *p2 = tmp;
}
void Selectsort(int* a, int n)
{
  int left = 0;
  int right = n - 1;
  while (right > left)
  {
  int min = left;
  int max = left;
  int i = 1;
  for (i = left+1; i <= right; i++)
  {
    if (a[i] > a[max])
    {
    max = i;
    }
    if (a[i] < a[min])
    {
    min = i;
    }
  }
  Swap(&a[left], &a[min]);
  //如果最大的数据在第一个位置,需要进行调整
  if (max == left)
  {
    max = min;
  }
  Swap(&a[right],&a[max]);
  left++;
  right--;
  }
}


341cca73d75fa35301f2ab4659353035_31446227010d49bf8a9b64eafa8004a3.png


选择排序的特点


效率不高

时间复杂度:O(N^2)

空间复杂度:O(1)

稳定性:不稳定


堆排序


在上一篇博客中有详细介绍堆排序,这里就不再赘述需要注意的是

升序:建大堆

降序:建小堆


算法实现


void Adjustdown(int* a, int n, int i)
{
  int minchild = 2 * i + 1;
  while (minchild < n)
  {
  if (minchild + 1 < n && a[minchild + 1] > a[minchild])
  {
    minchild++;
  }
  if (a[minchild] > a[i])
  {
    Swap(&a[minchild], &a[i]);
    i = minchild;
    minchild = 2 * i + 1;
  }
  else
  {
    break;
  }
  }
}
void Heapsort(int* a, int n)
{
  int i = 0;
  for (i = (n - 1 - 1) / 2; i >= 0; i--)
  {
     //向下调整
  Adjustdown(a, n, i);
  }
  i = 1;
  while (i < n)
  {
  Swap(&a[0], &a[n - i]);
  Adjustdown(a, n - i, 0);
  i++;
  }
}


堆排序的特点


效率很高

时间复杂度:O(N*logN)

空间复杂度:O(1)

稳定性:不稳定


冒泡排序


思路:

它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(后一个数大于前一个数)错误就把他们交换过来。走访元素的工作是重复地进行,直到没有相邻元素需要交换,也就是说该元素列已经排序完成


就类似气泡一样,越往后越大


图形展示


44df4dde68f1b574b4070dbf089d557b_721cbd47b8e24bc58b15115302e21021.png


算法实现


void Bubblesort(int* a, int n)
{
  int j = 0;
  for (j = 1; j <= n; j++)
  {
  int i = 0;
  int exchange = 1;
  for (i = 0; i < n - j; i++)
  {
    if (a[i] > a[i+1])
    {
    Swap(&a[i], &a[i + 1]);
    }
    else
    {
    exchange = 0;
    }
  }
  if (exchange == 1)
  {
    break;
  }
  }
}


冒泡排序的特点


非常容易理解

时间复杂度:O(N^2)

空间复杂度:O(1)

稳定性:稳定


目录
相关文章
|
机器学习/深度学习 算法 程序员
C++ Algorithm 库 算法秘境探索(Algorithm Wonderland Exploration)
C++ Algorithm 库 算法秘境探索(Algorithm Wonderland Exploration)
594 1
模拟电路的介绍
一、基本电路元件的应用 模拟电路最早的应用是基于基本电路元件的构建,如电阻、电容和电感等。这些基本电路元件可以通过串联、并联和反馈等方式组合成各种电路,用于模拟信号的处理和传输。基本电路元件的应用为模拟电路的发展奠定了基础。 二、放大器的出现 放大器是模拟电路中最重要的组成部分之一,它能够将输入信号放大到所需的幅度。最早的放大器是由电子管构成的,通过电子管的放大特性来实现信号的放大。随着半导体技术的发展,晶体管放大器和集成电路放大器相继出现,使得放大器的性能得到了大幅提升。 三、滤波器的应用 滤波器是模拟电路中常用的电路元件,它能够选择性地通过或者抑制特定频率的信号。滤波器的应用使得模拟电
324 0
|
缓存 前端开发 JavaScript
前端架构思考:代码复用带来的隐形耦合,可能让大模型造轮子是更好的选择-从 CDN 依赖包被删导致个站打不开到数年前因11 行代码导致上千项目崩溃谈谈npm黑洞 - 统计下你的项目有多少个依赖吧!
最近,我的个人网站因免费CDN上的Vue.js包路径变更导致无法访问,引发了我对前端依赖管理的深刻反思。文章探讨了NPM依赖陷阱、开源库所有权与维护压力、NPM生态问题,并提出减少不必要的依赖、重视模块设计等建议,以提升前端项目的稳定性和可控性。通过“left_pad”事件及个人经历,强调了依赖管理的重要性和让大模型代替人造轮子的潜在收益
275 0
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp微信小程序的社区垃圾回收管理系统的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的社区垃圾回收管理系统的详细设计和实现
215 0
基于SpringBoot+Vue+uniapp微信小程序的社区垃圾回收管理系统的详细设计和实现
|
数据安全/隐私保护 C++
【C++】凯撒密码 实现加密与解密
【C++】凯撒密码 实现加密与解密
|
11月前
|
安全 算法 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
在数字化时代,网络安全和信息安全已成为全球关注的焦点。随着技术的不断进步,网络攻击手段也在不断演变,给个人和企业带来了前所未有的挑战。本文将深入探讨网络安全漏洞的成因、影响及防范措施,介绍加密技术的原理和应用,并强调提高安全意识的重要性。通过这些知识的分享,旨在帮助读者更好地理解网络安全的重要性,采取有效措施保护个人信息和资产安全。
140 0
|
机器学习/深度学习 安全 网络协议
Web安全-Linux网络命令
Web安全-Linux网络命令
93 1
|
设计模式 缓存 Java
从源码学习Java动态代理|8月更文挑战
从源码学习Java动态代理|8月更文挑战
128 0
|
运维 关系型数据库 OLAP
阿里云百炼 x AnalyticDB向量引擎, 搭积木式轻松开发专属大模型应用
对大模型应用跃跃欲试,但奈何技术栈复杂难以下手?已经进行试水,但缺乏调优手段无法保障召回率和问答准确度?自行搭建大模型、向量检索引擎、服务API等基础组件难以运维?大模型种类繁多,但缺乏行业模型和应用模板?阿里云百炼 x AnalyticDB向量引擎推出一站式企业专属大模型开发和应用平台,像搭积木一样轻松完成企业专属大模型应用的开发,提供应用API,可一键接入企业自己的业务应用对外提供服务。
1561 0
|
C++ Python
ROS学习-理解ROS节点
ROS学习-理解ROS节点
828 0
ROS学习-理解ROS节点