插入排序优化——超越归并排序的超级算法

插入排序及优化

  • 插入排序算法
    • 算法讲解
    • 数据模拟
    • 代码
  • 优化思路
    • 一、二分查找
    • 二、copy函数
  • 优化后代码
  • 算法的用途
    • 题目:数星星(POJ2352 star)
      • 输入输出格式
        • 输入格式:
        • 输出格式
      • 输入输出样例
        • 输入样例
        • 输出样例
    • 题目讲解
      • 步骤如下
      • AC 代码

在这里插入图片描述

插入排序算法

在了解如何改进插入排序之前,我们先要了解插入排序的基本算法:

算法讲解

插入排序对于少量元素的排序,是一个有效的算法 。

插入排序是一种简单的排序方法,它是将一个数据插入到已经排好序的有序数组,从而形成一个新的有序数组。

插入排序的工作方式像许多人排序扑克牌:

我们每次从桌子上拿走一张牌并将其插入到手中正确的位置。

为了找到它的正确位置,我们从右到左将它与手中的每张牌进行比较。

因此,手上的牌总是有序。

数据模拟

原本要排序的数为 5 3 4 2 9 1,从小到大排序。


3 5 4 2 9 1        // 将3放到合适的位置(5前面)

3 4 5 2 9 1        // 将4放到合适的位置(3、5中间)

2 3 4 5 9 1        // 将2放到合适的位置(最前面)

2 3 4 5 9 1        // 将9放到合适的位置(最后面)

1 2 3 4 5 9        // 将1放到合适的位置(最前面)

排序结束!!!

代码

#include <iostream>
using namespace std;
int n,a[2000];        //定义数据个数n,排序数组a
int main()
{
	cin >>n;        //输入个数
	for (int i=1;i<=n;i++)
		cin >>a[i];            //输入数据
    
	for (int i=2;i<=n;i++)    //第一个数本身只有一个元素,所有有序,因此不用参与排序
	{
		int j,k=a[i];        //记录下当前元素
		for (j=i-1;j>0;j--)
		{
			if (a[j]>k)        //若前面一个数大于当前元素
				a[j+1]=a[j];    //则将前面一个元素往后移动
			else
				break;        //否则:说明当前元素已经找到了合适的位置,推出循环
		}
		a[j+1]=k;        //将当前元素放入数组的合适的位置
        
		/*                        输出排序的过程
		for (int j=1;j<=n;j++)
			cout <<a[j] <<" ";
		cout <<endl;
		*/
	}
    
	for (int i=1;i<=n;i++)
		cout <<a[i] <<" ";        //输出排序好的数组
	return 0;
}

优化思路

我们发现,插入排序的过程浪费在了查找合适的位置上,那么怎么优化呢?

我们知道,插入排序一直在维护 前 i i i个数是有序的,那么如何快速在有序的数列中查找一个小于(或大于)自己的数呢?

一、二分查找

二分!!!!

那么这样我们就讲查找的时间从 O ( n ) O(n) O(n)缩短为 O ( n   l o g ( n ) ) O(n~log(n)) O(n log(n))!!

忍不住激动!!

可是找到位置不够,还要进行移动啊。移动的时间复杂度是 O ( n ) O(n) O(n)那么这样非但没有优化,反而还增加了查找的时间。。。

希望瞬间破灭!!

但是我会向它屈服吗???

吗?

明显不会!

二、copy函数

我们可以使用一个 S T L STL STL库里面的一个函数:

copy(a,a+n,a+1);

c o p y copy copy函数!!

这个函数可以在 O ( 1 ) O(1) O(1)的时间范围内将数组的某一段移动到,
使用方法:
以上面的操作为例子,这表明:

  • a a a数组的第 0 0 0位为开头
  • a a a数组的第 n − 1 n-1 n1位位结尾
  • 将它移动到开头位第 1 1 1位的位置

那么,这就好办了,只需要要讲两个结合起来,一个速度与归并排序相当,代码比归并排序简短许多的超级优化插入排序代码诞生了:

优化后代码

#include <bits/stdc++.h>
#define N 2000000
using namespace std;
int n,x,y,f,t[N],k[N];
int main() {
	scanf("%d",&n);
	for (int i=1; i<=n; i++) {
		scanf("%d",&x);
		f=upper_bound(t+1,t+i,x)-t;		//记录二分的位置
		copy(t+f,t+i,t+f+1);	//copy
		t[f]=x;		//存入数组
	}
	for (int i=1; i<=n; i++) {
		printf("%d ",t[i]);
	}
	return 0;
}

输入数据:

5
4 9 1021 54 3

输出数据:

3 4 9 54 1021

也是对了好吧~~

算法的用途

这个算法可以快速的在有序数列里面进行操作,也是异常的方便快捷,代码超级简短!!
下面给一道可以用这个算法解决的问题:

题目:数星星(POJ2352 star)

天文学家经常观察星象图。星象图中用平面上的点来表示一颗星星,每一颗星星都有一个笛卡尔坐标。设定星星的等级为其左下角星星的总数。天文学家们想知道星星等级的分布情况。
在这里插入图片描述

比如上图, 5 5 5号星星的等级为 3 3 3(其左下角有编号为 1 1 1 2 2 2 4 4 4星星共三颗)。 2 2 2号星星和 4 4 4号星星的等级为 1 1 1。在上图中只有一颗星星等级为 0 0 0,两颗星星等级为 1 1 1,一颗星星等级为 2 2 2,一颗星星等级为 3 3 3
给定一个星象图,请你写一个程序计算各个等级的星星数目。

输入输出格式

输入格式:

输入的第一行包含星星的总数 N ( 1 < = N < = 15000 ) N (1<=N<=15000) N(1<=N<=15000)。接下来 N N N行,描述星星的坐标 ( X , Y ) (X,Y) (X,Y) X X X Y Y Y用空格分开, 0 ≤ X , Y ≤ 32000 0\le X,Y\le 32000 0X,Y32000)。星象图中的每个点处最多只有一颗星星。所有星星按 Y Y Y坐标升序排列。 Y Y Y坐标相等的星星按 X X X坐标升序排列。

输出格式

输出包含 N N N行,每行一个整数。第一行包含等级 0 0 0的星星数目,第二行包含等级 1 1 1的星星数目,依此类推,最后一行包含等级为 N − 1 N-1 N1的星星数目。

输入输出样例

输入样例

5
1 1
5 1
7 1
3 3
5 5

输出样例

1
2
1
1
0

题目讲解

由于输入数据有序,所以在第 i i i颗星星左下角的星星一定在 i i i前面!!原理自己想想就知道了~~

所以其实就是求在点 i i i前面的点中,有多少个的 X X X坐标是比 i i i X X X坐标要小的,因此直接考虑插入排序做法:

步骤如下

  • 输入星星的数量 n n n
  • 循环从 1 1 1 n n n
  • 每次输入当前点的 X X X Y Y Y
  • 用二分查找当前点的 X X X应当放在哪个位置
  • 用变了量 f f f记录位置, f − 1 f-1 f1就是当前星星的等级
  • c o p y copy copy将数据,从当前合适的位置开始,到 i − 1 i-1 i1往后移动一位
  • 将当前数据存入排序数组
  • 用另一个数组标记这个等级的星星 + + ++ ++
  • 循环输出每个级别的星星

AC 代码

#include <bits/stdc++.h>
#define N 20000
using namespace std;
int n,x,y,f,t[N],k[N];
int main() {
	scanf("%d",&n);
	for (int i=1; i<=n; i++) {
		scanf("%d%d",&x,&y);
		f=upper_bound(t+1,t+i,x)-t;
		copy(t+f,t+i,t+f+1);
		t[f]=x;
		k[f-1]++;
	}
	for (int i=0; i<n; i++) {
		printf("%d\n",k[i]);
	}
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

排序(七种排序)

1.插入排序 2.希尔排序 3.选择排序 4.堆排序 5.冒泡排序 6.快速排序 7.归并排序 1.插入排序 1.1思路 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为 止&#xff0c;得到一个新的有序序列 1.2实现 //插入排…

【BASH】回顾与知识点梳理(三十六)

【BASH】回顾与知识点梳理 三十六 三十六. 认识与分析登录档36.1 什么是登录档CentOS 7 登录档简易说明登录档的重要性Linux 常见的登录档档名登录档所需相关服务 (daemon) 与程序CentOS 7.x 使用 systemd 提供的 journalctl 日志管理 登录档内容的一般格式 36.2 rsyslog.servi…

C#程序配置读写例子 - 开源研究系列文章

今天讲讲关于C#的配置文件读写的例子。 对于应用程序的配置文件&#xff0c;以前都是用的ini文件进行读写的&#xff0c;这个与现在的json类似&#xff0c;都是键值对应的&#xff0c;这次介绍的是基于XML的序列化和反序列化的读写例子。对于ini文件&#xff0c;操作系统已经提…

JavaScript 进阶 第四天

深浅拷贝异常处理处理this性能优化 一. 深浅拷贝 深浅拷贝只针对引用类型 1.1 浅拷贝 拷贝的是地址常见方法 &#xff08;1&#xff09;拷贝对象&#xff1a;Object.assign() / 展开运算符 {...obj} &#xff08;2&#xff09;拷贝数组&#xff1a;Array.prototype.c…

Centos 8 网卡connect: Network is unreachable错误解决办法

现象1、ifconfig没有ens160配置 [testlocalhost ~]$ ifconfig lo: flags73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopba…

windows安装使用RocketMQ常见问题,及springboot整合

win安装rocketmq 官网下载二进制包&#xff1a;https://rocketmq.apache.org/download 解压到不包含中文及空格的目录&#xff0c;配置环境变量 ROCKETMQ_HOME4. 修改runbroker.cmd和runserver.cmd文件 文件地址在rocketmq安装目录下的bin文件夹中。 如果不修改可能会遇见以…

opencv进阶03-图像与鼠标的交互示例

在处理图像时&#xff0c;可能需要与当前正在处理的图像进行交互。OpenCV 提供了鼠标事件&#xff0c;使用户可以通过鼠标与图像交互。鼠标事件能够识别常用的鼠标操作&#xff0c;例如&#xff1a;针对不同按键的单击、双击&#xff0c;鼠标的滑动、拖曳等。 例如&#xff0c;…

windows搭建WebDAV服务,并内网穿透公网访问【无公网IP】

windows搭建WebDAV服务&#xff0c;并内网穿透公网访问【无公网IP】 文章目录 windows搭建WebDAV服务&#xff0c;并内网穿透公网访问【无公网IP】1. 安装IIS必要WebDav组件2. 客户端测试3. cpolar内网穿透3.1 打开Web-UI管理界面3.2 创建隧道3.3 查看在线隧道列表3.4 浏览器访…

数字化转型能带来哪些价值?_光点科技

随着科技的迅猛发展&#xff0c;数字化转型已成为企业和组织的一项重要战略。它不仅改变了商业模式和运营方式&#xff0c;还为各行各业带来了诸多新的机遇和价值。在这篇文章中&#xff0c;我们将探讨数字化转型所能带来的价值。 数字化转型能够显著提升效率和生产力。通过引入…

Ubuntu 20.04使用Livox mid 360 测试 FAST_LIO

前言 Livox mid360需要使用Livox-SDK2&#xff0c;而非Livox-SDK&#xff0c;以及对应的livox_ros_driver2 。并需要修改FAST_LIO中部分代码。 1. 安装Livox-SDK2 参考官方教程。 1.1. 安装CMake sudo apt install cmake1.2. 安装编译Livox-SDK2 git clone https://github…

C++多态

一、多态的定义及实现 多态是在不同继承关系的类对象&#xff0c;去调用同一函数&#xff0c;产生了不同的行为。比如Student继承了 Person。Person对象买票全价&#xff0c;Student对象买票半价。 构成多态的两个条件&#xff1a; 1、必须通过基类的指针或者引用调用虚函数…

废品回收抢单派单小程序开源版开发

废品回收抢单派单小程序开源版开发 用户注册和登录&#xff1a;用户可以通过手机号码注册和登录小程序&#xff0c;以便使用废品回收抢单派单功能。废品回收订单发布&#xff1a;用户可以发布废品回收订单&#xff0c;包括废品种类、数量、回收地点等信息。废品回收抢单&#…

【python知识点】锦集

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/132368704 出自【进步*于辰的博客】 相关博文&#xff1a;【python细节、经验】锦集。 注&#…

陕西科技大学改考408!附考情分析

改考信息 8月14日&#xff0c;陕西科技大学公布了2024年硕士研究生招生目录&#xff08;初稿&#xff09;&#xff0c;其中不难发现083500软件工程初试专业课由819数据结构改为408计算机学科专业基础 图片&#xff1a;陕西科技大学24专业目录-软件工程学硕 https://yjszs.sus…

MySQL数据库概述

MySQL数据库概述 1 SQL SQL语句大小写不敏感。 SQL语句末尾应该使用分号结束。 1.1 SQL语句及相关操作示例 DDL&#xff1a;数据定义语言&#xff0c;负责数据库定义、数据库对象定义&#xff0c;由CREATE、ALTER与DROP三个语法所组成DML&#xff1a;数据操作语言&#xff…

【C++】 使用红黑树模拟实现STL中的map与set

文章目录 前言1. 对之前实现的红黑树进行一些补充和完善1.1 析构1.2 查找 2. STL源码中map和set的实现3. 改造红黑树封装map和set3.1 红黑树结构修改3.2 map、set的结构定义3.3 insert的封装3.4 insert测试3.5 发现问题并解决3.6 红黑树迭代器实现3.7 封装set和map的迭代器并测…

svg图片如何渲染到页面,以及svg文件的上传

svg图片渲染到页面的几种方式 背景&#x1f7e1;require.context获取目录下的所有文件&#x1f7e1;方式1: 直接在html中渲染&#x1f7e1;方式: 发起ajax请求&#xff0c;获取SVG文件 背景 需要实现从本地目录下去获取所有的svg图标进行预览&#xff0c;将选中的图片显示在另…

报道|新鲜出炉!INFORMS公布六位新任期刊主编

推文作者&#xff1a;徐思坤 编者按 INFORMS旗下的六本期刊&#xff0c;Management Science、Operations Research、Service Science、Tutorials in OR、INFORMS Analytics Collection&#xff0c;以及Transportation Science的新任主编公布&#xff0c;并将于2024年1月1日正式…

基于微信小程序的上门维修评价系统_22c7h-

随着科学研究的不断深入&#xff0c;有关上门维修的各种信息量也在成倍增长。面对庞大的信息量&#xff0c;就需要有上门维修系统来提高管理工作的效率。通过这样的系统&#xff0c;我们可以做到信息的规范管理和快速查询&#xff0c;从而减少了管理方面的工作量。 建立基于微信…

CentOS ens160 显示disconnected

使用nmcli device查看网卡状态&#xff0c;显示如图&#xff1a; 检查宿主机系统VMware DHCP Sevice和VMware NAT Sevice服务是否正常运行。 右键点击我的电脑管理按钮&#xff0c;打开计算机管理点击服务