【算法基础】排序 插入、归并、堆、快速 升序+降序

news2025/2/26 14:23:03

目录

1.排序

1.1 插入排序

1.2 归并排序

1.3 推排序

1.4 快速排序


1.排序

1.1 插入排序

  • 时间复杂度:O(n)~O(n*n)

  • 空间复杂度:O(1)

  • 稳定

img

 

  • 步骤:

    1.设第一个元素为有序列。

    2.取有序列后面的一个元素。

    3.将该元素插入到有序列中的正确位置。

    4.依次重复3、4步,直到完成排序。

#include<iostream>
using namespace std;
​
//插入升序
void insert_sort_asc(int* arr, int n)
{
     for (int i = 0; i < n - 1; i++)
     {
          int end = i;//有序列的最后一个元素
          int temp = arr[end + 1];//当前需要插入排序的元素
​
          while (end>=0)//最坏情况下,遍历至有序列的第一个元素
          {
               if (temp < arr[end]) //待插入的数小,就将大数往后移
               {
                    arr[end + 1] = arr[end];//后移
                    end--;//向前继续找位置
               }
               else
               {
                    break;//temp更大,则找到要插入的位置,退出循环
               }
          }
          arr[end+1] = temp;//temp插在较小数后
     }
}
​
//插入降序
void insert_sort_dec(int* arr, int n)
{
     for (int i = 0; i < n - 1; i++)
     {
          int end = i;
          int temp = arr[end+1];
          while (end>=0)
          {
               if (temp > arr[end])
               {
                    arr[end + 1] = arr[end];
                    end--;
               }
               else
               {
                    break;
               }
          }
          arr[end + 1] = temp;
     }
}
​
void output(int* arr, int n)
{
     for (int i = 0; i < n; i++)
     {
          cout << arr[i] << " ";
     }
     cout << endl;
}
​
int main()
{
     int n, arr[99],copy[99];
     cout << "Number of inputs:";
     cin >> n;
     cout << "Inputs array:";
     for (int i = 0; i < n; i++)
     {
          cin >> arr[i];
     }
     memcpy(copy, arr, n * sizeof(int));
​
     insert_sort_asc(copy, n);
     output(copy, n);
     insert_sort_dec(arr, n);
     output(arr, n);
}

1.2 归并排序

  • 时间复杂度:O(n\log n)

  • 时间复杂度:O(n)

  • 稳定

 

uploading.4e448015.gif

正在上传…

重新上传

  • 分治算法

    分:将数组分为各小部分。

    治:各小部分排序。

    img

    • 步骤

      • 分的步骤:

        1.计算中点mid;

        2.将mid左边和右边递归继续分,直到分到每一小部分只有一个元素;

        3.结合每两个小部分排序,直到所有分开的部分重新合起来。

      • 治的步骤(排序的步骤):

        1.取要合并的两部分首元素,比较大小;

        2.若升序排列,则取两部分中较小的一个,加入新数组;

        3.重复1,2步骤,直到有一部分被全部取完。

    •  

#include<iostream>
using namespace std;
#define N 9999
​
void merger_sort_asc(int* arr, int l, int r);
void merger_sort_dec(int* arr, int l, int r);
​
void process_asc(int* arr, int l, int r)
{
     if (l == r)return;//分到最小时返回(每组只有一个元素)
​
     //计算中点时不用(r+l)/2,是为了防止r+l溢出
     int mid = l + (r - l) / 2;//计算中点
     process_asc(arr, l, mid);//继续分治左部分
     process_asc(arr, mid + 1, r);//继续分治右部分
     merger_sort_asc(arr, l,r);//各部分排序
}
​
void merger_sort_asc(int* arr, int l,int r)
{
     int mid = l + (r - l) / 2;
     int i = l;//第一部分首元素
     int j = mid + 1;//第二部分首元素
     int temp[N];//临时数组存放
     int k = 0;//临时数组下标
​
     //比较
     while (i <= mid && j <= r)
     {
          //两部分中首元素比大小,哪个小就把哪个放入临时数组
          temp[k++] = (arr[i] < arr[j]) ? arr[i++] : arr[j++];
     }
​
     //若其中一部分已经取完,另外一部分有剩余元素
     while (i<=mid)
     {
          temp[k++] = arr[i++];
     }
     while (j <= r)
     {
          temp[k++] = arr[j++];
     }
​
     //把排好序的临时数组放入原数组
     for (int t = l; t <= r; t++)
     {
          arr[t] = temp[t-l];//原数组下标从l开始,临时数组从0开始
     }
}
​
​
void process_dec(int* arr, int l, int r)
{
     if (l == r)return;
     int mid = l + (r - l) / 2;
     process_dec(arr, l, mid);
     process_dec(arr, mid + 1, r);
     merger_sort_dec(arr, l, r);
}
​
void merger_sort_dec(int* arr, int l, int r)
{
     int mid = l + (r - l) / 2;
     int i = l, j = mid + 1;
     int k = 0, temp[N];
​
     while (i <= mid && j <= r)
     {
          temp[k++] = (arr[i] > arr[j]) ? arr[i++] : arr[j++];
     }
     while (i <= mid)
     {
          temp[k++] = arr[i++];
     }
     while (j <= r)
     {
          temp[k++] = arr[j++];
     }
​
     for (int t = l; t <= r; t++)
     {
          arr[t] = temp[t - l];
     }
}
​
void output(int* arr,int n)
{
     for (int i = 0; i < n; i++)
     {
          cout << arr[i]<<" ";
     }
     cout << endl;
}
​
int main()
{
     int n;
     int arr[N],copy[N];
     cout << "The number of input:";
     cin >> n;
     cout << "Input the array:";
     for (int i = 0; i < n; i++)
     {
          cin >> arr[i];
     }
     memcpy(copy, arr, n * sizeof(int));
​
     process_asc(arr, 0, n - 1);
     output(arr, n);
​
     process_dec(copy, 0, n - 1);
     output(copy, n);
}

*分治核心思想

  • 使用场景:大问题难以解决,小问题容易解决。

1.把大问题拆解成小问题(递归)。 2.处理每个小问题。 3.合并每个小问题,解决大问题(递归)。

1.3 推排序

a.堆

  • 分类:

    • 大根堆:父结点比左孩子和右孩子大。

    • 小根堆:父结点比左孩子和右孩子小。

  • 在数组中表示:

  •  

b.堆排序

  • 性能

    空间复杂度:O(1)

    时间复杂度:O(nlogn)

    不稳定

  • 在这里插入图片描述

  • 排序步骤

    升序大根堆,降序小根堆。

    1.将数组构造成大根堆(堆顶==最大值);

    2.将堆顶与堆末交换,相当于把堆分为没有排好序的堆顶和排好序的堆尾;

    3.将剩余n-1个数再构造成大根堆;

    4.将堆顶与n-1处的数交换;

    5.如此重复,直到排完。

  • 构造大根堆步骤

    1.从最后一棵子树开始比较(从后往前);

    2.通过父结点和子结点值的交换,将每棵子树的最大值作为父结点(从上到下);

    3.直到构成大根堆。

#include<iostream>
#include<algorithm>
using namespace std;
​
//降序
//调整当前小堆,parent是小堆堆顶
void down(int* arr, int parent,int n)
{
     //定义这个子堆中的父子
     int child = parent * 2 + 1;//左孩子
​
     //孩子超过数组下标结束
     while (child < n)
     {
          //保证child是左右孩子中最小的
          //且要保证有右孩子
          if (child + 1 < n && arr[child + 1] < arr[child])
          {
               child++;
          }
          //小的往上,大的往下
          if (arr[child] < arr[parent])
          {
               swap(arr[child], arr[parent]);//换父子值
               //换父子下标
               parent = child;
               child = parent * 2 + 1;
          }
          else
          {
               break;
          }
     }
}
void heap_sort_dec(int* arr, int n)
{
     //建小堆
     //从最后一个小堆开始,i是小堆父结点
     for (int i = (n-2) / 2; i>=0; i--)
     {
          down(arr,i,n);
     }
     int end=n-1;
     while (end>0)
     {
          swap(arr[end], arr[0]);//交换堆顶(用最后一个数覆盖第一个)
          down(arr, 0, end--);//新堆再造小根堆
     }
}
​
//升序
void up(int* arr, int parent, int n)
{
     int child = parent*2+1;
     while (child <n)
     {
          //选出最大孩子
          if (child + 1 < n && arr[child + 1] > arr[child])
          {
               child++;
          }
          //小的往下,大的往上
          if (arr[child] > arr[parent])
          {
               swap(arr[child], arr[parent]);//换父子值
               //换父子下标
               parent = child;
               child = parent * 2 + 1;
          }
          else
          {
               break;
          }
     }
}
void heap_sort_asc(int* arr, int n)
{
     for (int i = (n-2)/2; i >=0; i--)
     {
          up(arr, i, n);
     }
     int end = n - 1;
     while (end > 0)
     {
          swap(arr[0], arr[end]);
          up(arr, 0, end);
          end--;
     }
}
​
void output(int* arr, int n)
{
     for (int i = 0; i < n; i++)
     {
          cout << arr[i] << " ";
     }
     cout << endl;
}
​
int main()
{
     int n,arr[999],copy[999];
     cin >> n;
     for (int i = 0; i < n; i++)
     {
          cin >> arr[i];
          copy[i] = arr[i];
     }
     heap_sort_asc(arr, n);
     output(arr, n);
     heap_sort_dec(copy, n);
     output(copy, n);
}

1.4 快速排序

  • 主要思想:冒泡排序的分治。

  • 步骤: 1.确定分界点x,为 x=q [ (left+right) / 2 ] ; 2.调整数组,使之成为

  •  

  • 调整方法:1) i从left开始向右找>=x的数,得q[ i ]; 2) j从left开始向左找<=x的数,得q[ j ]; 3)如果 i<j ,说明还没有调整完成,则交换q[ i ] and q[ j ];若 i>=j 说明已经调整完。

3.x左右两边递归

#include<iostream>
#include<algorithm>
using namespace std;
​
//升序
void quick_sort_asc(int* arr, int l, int r)
{
     if (l >= r)return;
     int x = arr[l + (r - l) / 2];
     int i = l - 1, j = r + 1;
     while (i < j)
     {
          //找出左边大于x的数组下标i
          do i++; while (arr[i] < x);
          //找出右边小于x的数组下标j
          do j--; while (arr[j] > x);
          //如果左右都找到了符合条件的值
          if (i < j)
          {
               swap(arr[i], arr[j]);
          }
     }
     quick_sort_asc(arr, l, j);
     quick_sort_asc(arr, j + 1, r);
}
​
//降序
void quick_sort_dec(int* arr, int l, int r)
{
     if (l >= r)return;
     int i = l - 1, j = r + 1;
     int x = arr[l + (r - l) / 2];
     while (i < j)
     {
          do i++; while (arr[i] > x);
          do j--; while (arr[j] < x);
          if (i < j)
          {
               swap(arr[i], arr[j]);
          }
     }
     quick_sort_dec(arr, l, j);
     quick_sort_dec(arr, j + 1, r);
}
​
void output(int* arr, int n)
{
     for (int i = 0; i < n; i++)
     {
          cout << arr[i]<<" ";
     }
     cout << endl;
}
​
int main()
{
     int n, arr[999];
     cin >> n;
     for (int i = 0; i < n; i++)
     {
          cin >> arr[i];
     }
     quick_sort_asc(arr, 0, n - 1);
     output(arr, n);
     quick_sort_dec(arr, 0, n - 1);
     output(arr, n);
}

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

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

相关文章

【C语言学习笔记】:一维数组指针,二维数组指针

数组&#xff08;Array&#xff09;是一系列具有相同类型的数据的集合&#xff0c;每一份数据叫做一个数组元素&#xff08;Element&#xff09;。数组中的所有元素在内存中是连续排列的&#xff0c;整个数组占用的是一块内存。以int arr[] { 99, 15, 100, 888, 252 };为例&am…

Linux | 调试器GDB的详细教程【纯命令行调试】

文章目录一、前言二、调试版本与发布版本1、见见gdb2、程序员与测试人员3、为什么Release不能调试但DeBug可以调试❓三、使用gdb调试代码1、指令集汇总2、命令演示⌨ 行号显示⌨ 断点设置⌨ 查看断点信息⌨ 删除断点⌨ 开启 / 禁用断点⌨ 运行 / 调试⌨ 逐过程和逐语句⌨ 打印 …

C/C++开发,无可避免的多线程(篇二).thread与其支持库

一、原子类型与原子操作 1.1 原子类型与操作介绍 在前一篇博文中&#xff0c;多线程交互示例代码中&#xff0c;给出了一个原子类型定义&#xff1a; // 原子数据类型 atomic_llong total {0}; 那么什么事原子数据类型呢&#xff0c;和c的基础数据类型有什么不同呢&#xff1a…

实验一 Python编程基础

目录 一、实验目标 二、实验内容 1.绘制如下图形 &#xff0c;一个正方形&#xff0c;内有三个红点&#xff0c;中间红点在正方形中心。 2.使用turtle库绘制如下图形&#xff1a; 3.绘制奥运五环图 4.回文问题 5.身份证性别判别 6.数据压缩 7.验证哥德巴赫猜想 8.使…

JVM常用指令

JVM常用指令1.准备工作2.jps3. jconsole4.jstat5.jstack6.jmap7.jvisualvm工具8.自动dump内存信息1.准备工作 在idea中编写代码 public class JVMTest {Testpublic void test() throws InterruptedException {while (true) {Thread.sleep(1000);System.out.println(123);}} }…

Unity 入门精要01---标准光照模型

本节基础知识结构 基础光照部分 环境光 在标准光照模型中&#xff0c;我们会环境光来代替间接光照 Cambient g amient 我们可以在Windows->Rendering->Lighting->Enviroment进行修改Ambient 的Color 自发光 直接在最后片元着色器输出颜色之前把材质的自发光颜色添…

深圳大学计软《面向对象的程序设计》实验13 运算符重载

A. 三维坐标点的平移&#xff08;运算符重载&#xff09; 题目描述 定义一个三维点Point类&#xff0c;利用友元函数重载"“和”–"运算符&#xff0c;并区分这两种运算符的前置和后置运算。 要求如下&#xff1a; 1.实现Point类&#xff1b; 2.编写main函数&a…

关于2023年造林施工、林业设计资质,新办、年审的最新通知!

一、资质类别省林学会本年度开展认定的资质种类包括&#xff1a;造林绿化类&#xff08;含施工资质、监理资质&#xff09;、林业有害生物防治类&#xff08;含防治资质、监理资质&#xff09;和林业调查规划设计类。二、认定标准资质认定执行以下标准&#xff1a;1.造林绿化施…

边缘计算:万字长文详解高通SNPE inception_v3安卓端DSP推理加速实战

本文是在以下文章的基础上编写&#xff0c;关于SNPE环境部署和服务器端推理可以参考上一篇文章&#xff1a; 边缘计算&#xff1a;万字长文详解高通SNPE inception_v3推理实战_seaside2003的博客-CSDN博客 本文最/关键的是利用SNPE在安卓环境不同的runtimes&#xff08;CPU/G…

高通 Android10/12 4 6dof Camera+2RGBCamera异常处理经验总结

1 背景&#xff1a;此需求apk距离之前更改时间将近9个月&#xff0c;我们这边原来跟驱动那边对接指令和角度 后续没有改过&#xff0c;测试部说apk cameaid提示信息不正确。 2 原因&#xff1a;因为之前用的1.0基线&#xff08;Android 10) 后面由于客户功能需求变更&#xff…

进程信号生命周期详解

信号和信号量半毛钱关系都没有&#xff01; 每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到,例如其中有定 义 #define SIGINT 2 查看信号的机制&#xff0c;如默认处理动作man 7 signal SIGINT的默认处理动作是终止进程&#xff0c;SIGQUIT的默认处理…

23届春招结束_分享java岗面试心得

23届春招结束_分享java岗面试心得 从一月10日开始投简历&#xff0c;经历了两个月的面试与学习&#xff0c;成功拿到了12k13薪的国企offer&#xff0c;春招结束了 一、经历秋招&#xff0c;被所谓的金九银十给坑惨了 在秋招的时候&#xff0c;经过网友&#xff08;美团java岗…

九龙证券|利好政策密集发布,机构扎堆看好的高增长公司曝光

新能源轿车销量和保有量快速增长&#xff0c;带来了充电桩商场的微弱需求。 日前&#xff0c;商务部部长王文涛表明&#xff0c;本年将在落实好方针的一起&#xff0c;活跃出台新方针办法&#xff0c;比方辅导当地展开新能源轿车下乡活动&#xff0c;优化充电等使用环境&#x…

Vue3中的h函数

文章目录简介简单使用参数使用计数器进阶使用函数组件插槽专栏目录请点击 简介 众所周知&#xff0c;vue内部构建的其实是虚拟DOM&#xff0c;而虚拟DOM是由虚拟节点生成的&#xff0c;实质上虚拟节点也就是一个js对象事实上&#xff0c;我们在vue中写的template,最终也是经过…

Unity RectTransform Scale Handler - 如何在Runtime运行时拖动缩放窗口尺寸

文章目录简介变量说明实现光标移入移出鼠标拖动距离Anchor 锚点目标尺寸扩展方向简介 本文介绍如何在Runtime运行时拖动缩放UI窗口的尺寸&#xff0c;如图所示&#xff0c;在示例窗口的左上、上方、右上、左方、右方、左下、下方、右下&#xff0c;分别放置了一个拖动柄&#…

Spring之基于注解方式实例化BeanDefinition(1)

最近开始读Spring源码&#xff0c;读着读着发现里面还是有很多很好玩的东西在里面的&#xff0c;里面涉及到了大量的设计模式以及各种PostProcessor注入的过程&#xff0c;很好玩&#xff0c;也很复杂&#xff0c;本文就是记录一下我学习过程中的主干流程。 在开始我们源码解读…

2023年湖北武汉中级工程师怎么申请?申报渠道有哪些?启程别

2023年湖北武汉中级工程师怎么申请?申报渠道有哪些&#xff1f;启程别 武汉市中级工程师怎么报名&#xff1f;很多人不知道中级职称怎么申请&#xff0c;在哪里申请&#xff0c;那么启程别来告诉大家&#xff0c;启程别是谁&#xff0c;进入百度搜索启程别就知道啦 武汉中级工…

【学习Docker(七)】详细讲解Jenkins部署SpringCloud微服务项目,Docker-compose启动

Jenkins部署SpringCloud微服务项目&#xff0c;Docker-compose启动 座右铭&#xff1a;《坚持有效输出&#xff0c;创造价值无限》 本文介绍使用Jenkins部署SpringCloud微服务项目&#xff0c;Docker-compose启动。 之前写过安装Jenkins的过程&#xff0c;这里就不写安装细节了…

[oeasy]python0099_雅达利大崩溃_IBM的开放架构_兼容机_oem

雅达利大崩溃 回忆上次内容 个人计算机浪潮已经来临 苹果公司迅速发展微软公司脱离mits准备做纯软件公司IBM用大型机思路制作的5100惨败 Commodore 64 既做计算机又做游戏机 计算机行业和游戏行业 跟随着底层技术不断迭代已经进入了战乱纷纷的年代最终又会如何呢&#xff1f…

31 openEuler使用LVM管理硬盘-管理物理卷

文章目录31 openEuler使用LVM管理硬盘-管理物理卷31.1 创建物理卷31.2 查看物理卷31.3 修改物理卷属性31.4 删除物理卷31 openEuler使用LVM管理硬盘-管理物理卷 31.1 创建物理卷 可在root权限下通过pvcreate命令创建物理卷。 # pvcreate [option] devname ...其中&#xff1…