【数据结构】-8种排序解析(详细总结,简洁,含代码,例题)(一)

简介: 【数据结构】-8种排序解析(详细总结,简洁,含代码,例题)

一.8种排序方式总览分析(带图)

   1.按方式分类(比较排序)

image.png

*计数排序:非比较排序

二.8种排序方式详细解析

    1.计数排序

注意:计数排序适合范围集中,且范围不大的整型数组排序。不适合范围分散或者非整型的排序,如:字符串、浮点数 等


步骤:


1.找到原数组最大的值,记作range


2.设置一个计数数组,遍历一遍原数组O(n),统计每个数据出现的次数。


3.遍历一遍计数数组O(range)


计数排序分为:相对映射型和非相对映射型(相对位置)


图示意:

image.png

 2.冒泡排序

遍历有序区间的各个数,从其开始到结尾的区间内轮转交换不断缩小区间

原理:不断把大/小的数移到后面

注意点:为提高效率,当发现一次循环中没有数对交换,即可中止循环。

void BubbleSort(int*a,int n)
{
  int i = 0,j=0;
  for (j = 0; j<n; j++)
  {
    bool exchange = false;
    for (i = 0; i < n-j; i++)
    {
      if (a[i + 1] < a[i])
      {
        Swap(&a[i + 1], &a[i]);
        exchange = true;
      }
    }
        //加入判断环节,提前终止,提高效率
    if (exchange == false)
    {
      break;
    }
  }
}

    3.选择排序

遍历有序区间的各个数,找出其之后的最大/最小数并与该数之后的数进行替换。


代码的设计思路是设置left,right下标从数组两端向中间遍历,依次筛选出最大值和最小值mini,maxi,并分别与left,riight进行交换。


注意点:在交换过程中,left所处的位置可能正好被maxi标记,接下来下一步maxi与right的交换则会出错,right无法与正确的maxi交换。


解决方法:如果left和maxi重叠,交换后要修正

void SelectSort(int* a, int n)
{
  int left = 0;
  int right = n;
  while (left < right)
  {
    int mini = left, maxi = right;
    for (int i =left+1; i <= right; i++)
    {
      if (a[i] > a[maxi])
      {
        maxi = i;//移动下标
      }
      if (a[i] < a[mini])
      {
        mini = i;
      }
    }
    Swap(&a[left], &a[mini]);
    if (left == maxi)
    {
      maxi = mini;
    }
    Swap(&a[right], &a[maxi]);
    left++;
    right--;
  }
}

 4.插入排序

遍历有序区间的各个数,把其视作临时变量tmp,分别于它前面的数进行对比,

其进一步优化即为“希尔排序”

注意点:此算法中,当tmp比第一个数大/小时,end会到-1的位置。所以采用图中标记用法

image.png

//升序
void InsertSort(int* a, int n)//a 数组  n 个数
{
  int i = 0;
  for (i = 1; i < n; i++)
  {
    int end = i - 1;
    int tmp = i;
    while (end >= 0)
    {
      if (a[tmp] < a[end])
      {
        //整体后移
        a[end + 1] = a[end];
        --end;
      }
      else
      {
        break;
      }
    }
    //填空
    a[end + 1] = a[tmp];
  }
}

5.希尔排序

其可以理解为在插入排序的基础上进行预排序(分组插排)

注意点:图示辅助理解循环:

image.png

void ShellSort(int* a, int n)
{
  //gap==1 插入排序
  //gap>1预先排序
  int gap=n;
  //升序
  while(gap>1)
  { 
    gap = gap / 2;
    //gap=gap/3+1     确保gap的跳跃到最后为1,
    int i = 0;
    for (i = 0; i < n-gap; i++)
    {
      int end = i;
      int tmp = i+gap;
      while (end >= 0)
      {
        if (a[tmp] < a[end])
        {
          //整体后移
          a[end + gap] = a[end];
          end -= gap;
        }
        else
        {
          break;
        }
      }
      //填空
      a[end + gap] = a[tmp];
    }
  }
}

 6.堆排序

详情可见博主关于堆排详解:

image.png

 7.快速排序(递归和非递归写法)

任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中的所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。


注意点:当快速排序接近二分(二叉树)的递归模式时,效率最高。因此引入“三数取中”优化代码:

int GetMidNumi(int* a, int left, int right)
{
  int mid = (left + right) / 2;
  if (a[left] < a[mid])
  {
    if (a[mid] < a[right])
    {
      return mid;
    }
    else if (a[left] > a[right])
    {
      return left;
    }
    else
    {
      return right;
    }
  }
  else // a[left] > a[mid]
  {
    if (a[mid] > a[right])
    {
      return mid;
    }
    else if (a[left] < a[right])
    {
      return left;
    }
    else
    {
      return right;
    }
  }
}

    1.三种排序方式

 1.交换法


  1.左边做key,右边先走——保证相遇位置比key小


    ps:【右边先走找比key小的数,则其停止位置一定小于等于key】


  2.由于左右相遇的位置一定比key小,把左边与相遇位置替换


图示:

image.png


image.png

代码:

2.挖坑法

  1.先将左边第一个数据放在临时变量key中,原地形成一个坑位

 2.右边先动,找小于key的数,放到坑位中,并且原地新生成一个坑位

 3.当左右相遇时,将key填入最后一个坑位中

1.png

3.前后指针法(玩区间)


 1.左边第一个数设为key,prev(延迟指针),cur(实时指针)


 2.cur开始向右移动,找到比key小的值prev和cur同时移动


 3.找到比key大的值只移动cur——保证prev和cur中间隔着一段比key大的区间


 4.找到比key小的值时,交换prev下一个位置(比key大的区间)和cur位置的值——比key大的值翻到区间右边,把比key小的值翻到区间左边。

图示:

2.png

相关文章
|
10月前
|
前端开发 Java
java实现队列数据结构代码详解
本文详细解析了Java中队列数据结构的实现,包括队列的基本概念、应用场景及代码实现。队列是一种遵循“先进先出”原则的线性结构,支持在队尾插入和队头删除操作。文章介绍了顺序队列与链式队列,并重点分析了循环队列的实现方式以解决溢出问题。通过具体代码示例(如`enqueue`入队和`dequeue`出队),展示了队列的操作逻辑,帮助读者深入理解其工作机制。
364 1
|
11月前
|
算法 PyTorch 算法框架/工具
昇腾 msmodelslim w8a8量化代码解析
msmodelslim w8a8量化算法原理和代码解析
931 5
|
搜索推荐 UED Python
实现一个带有昼夜背景切换的动态时钟:从代码到功能解析
本文介绍了一个使用Python和Tkinter库实现的动态时钟程序,具有昼夜背景切换、指针颜色随机变化及整点和半点报时功能。通过设置不同的背景颜色和随机变换指针颜色,增强视觉吸引力;利用多线程技术确保音频播放不影响主程序运行。该程序结合了Tkinter、Pygame、Pytz等库,提供了一个美观且实用的时间显示工具。欢迎点赞、关注、转发、收藏!
526 94
|
存储 机器学习/深度学习 算法
C 408—《数据结构》图、查找、排序专题考点(含解析)
408考研——《数据结构》图,查找和排序专题考点选择题汇总(含解析)。
956 29
|
11月前
|
传感器 监控 Java
Java代码结构解析:类、方法、主函数(1分钟解剖室)
### Java代码结构简介 掌握Java代码结构如同拥有程序世界的建筑蓝图,类、方法和主函数构成“黄金三角”。类是独立的容器,承载成员变量和方法;方法实现特定功能,参数控制输入环境;主函数是程序入口。常见错误包括类名与文件名不匹配、忘记static修饰符和花括号未闭合。通过实战案例学习电商系统、游戏角色控制和物联网设备监控,理解类的作用、方法类型和主函数任务,避免典型错误,逐步提升编程能力。 **脑图速记法**:类如太空站,方法即舱段;main是发射台,static不能换;文件名对仗,括号要成双;参数是坐标,void不返航。
460 5
|
12月前
|
人工智能 文字识别 自然语言处理
保单AI识别技术及代码示例解析
车险保单包含基础信息、车辆信息、人员信息、保险条款及特别约定等关键内容。AI识别技术通过OCR、文档结构化解析和数据校验,实现对保单信息的精准提取。然而,版式多样性、信息复杂性、图像质量和法律术语解析是主要挑战。Python代码示例展示了如何使用PaddleOCR进行保单信息抽取,并提出了定制化训练、版式分析等优化方向。典型应用场景包括智能录入、快速核保、理赔自动化等。未来将向多模态融合、自适应学习和跨区域兼容性发展。
|
SQL Java 数据库连接
如何在 Java 代码中使用 JSqlParser 解析复杂的 SQL 语句?
大家好,我是 V 哥。JSqlParser 是一个用于解析 SQL 语句的 Java 库,可将 SQL 解析为 Java 对象树,支持多种 SQL 类型(如 `SELECT`、`INSERT` 等)。它适用于 SQL 分析、修改、生成和验证等场景。通过 Maven 或 Gradle 安装后,可以方便地在 Java 代码中使用。
4175 11
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
355 59
|
8月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
186 0
栈区的非法访问导致的死循环(x64)
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
655 77

推荐镜像

更多
  • DNS