归并排序——逆序数对的统计

逆序数对的统计

题目描述

运行代码

#include <iostream>
using namespace std;
#define LL long long 
const int N = 1e5 + 5;
int a[N], tmp[N];
LL merge_sort(int q[], int l, int r)
{if (l >= r)return 0;  int mid = l + r >> 1;  LL res = merge_sort(q, l, mid) + merge_sort(q, mid + 1, r);    int k = 0, i = l, j = mid + 1;while (i <= mid && j <= r)if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];else{res += mid - i + 1;tmp[k ++ ] = q[j ++ ];}while (i <= mid)tmp[k ++ ] = q[i ++ ];while (j <= r)tmp[k ++ ] = q[j ++ ];for (i = l, j = 0; i <= r; i ++, j ++ )q[i] = tmp[j];  return res;
}
int main()
{int n;scanf("%d", &n);for (int i = 0; i < n; i ++ ) 
scanf("%d", &a[i]);    cout << merge_sort(a, 0, n - 1) << endl;  return 0;
}

代码思路

宏定义与常量

  • #define LL long long:定义LLlong long类型的别名,用于存储较大的整数,例如逆序对的数量。
  • const int N = 1e5 + 5;:定义数组的最大容量,适用于最多100,005个元素的数组。

函数merge_sort此函数递归地将数组分成更小的部分,然后合并这些部分,同时计算逆序对总数。

  • 参数q[]是要排序的数组,lr分别是当前子数组的左右边界(索引)。
  • 基础情况:当左边界大于等于右边界时(即子数组只有一个或没有元素),返回0,表示该子数组没有逆序对。
  • 分解:计算中间索引mid,递归地对左右两部分[l, mid][mid+1, r]进行排序并计算逆序对,将结果累加到res中。
  • 合并
    • 初始化辅助数组tmp和三个指针k, i, j。当i未超过midj未超过r时,比较q[i]q[j]的大小:
      • 如果q[i] <= q[j],说明当前元素不会形成新的逆序对,将q[i]放入tmp,并移动ik
      • 否则,所有q[i]q[mid]之间的元素都比q[j]大,因此增加了mid - i + 1个逆序对,将q[j]放入tmp,移动jk
    • 分别处理剩余的元素,将它们依次放入tmp。将tmp中的元素复制回原数组q
  • 返回值:最终返回整个数组排序过程中的逆序对总数res
  • 主函数main读取数组长度n。通过循环读取数组a中的每个元素。调用merge_sort函数,传入数组a和其边界(0和n-1),输出计算得到的逆序对总数。

改进思路

  • 使用指针直接操作数组:在mergeSortAndCount函数中,直接使用指针ijk而非索引,这在某些情况下可以略微提高访问效率。
  • 保持数组作为参数:继续使用原生数组作为函数参数,保持与原始代码结构的一致性。
  • 代码格式和可读性:调整代码格式,确保良好的可读性和一致性,比如增加必要的空格和换行。
  • 去除不必要的类型别名:保留int64_t作为长整型的别名,因为它清晰地表达了数据类型的目的。

改进代码

#include <iostream>
using namespace std;
typedef long long int64_t;
// 使用指针代替数组索引来优化访问速度
int64_t mergeSortAndCount(int a[], int temp[], int left, int right) {if (left >= right) return 0;   int mid = left + (right - left) / 2;   // 递归排序并计数int64_t inv_count = mergeSortAndCount(a, temp, left, mid);inv_count += mergeSortAndCount(a, temp, mid + 1, right);   // 合并阶段计算逆序对int i = left, j = mid + 1, k = left;while (i <= mid && j <= right) {if (a[i] <= a[j]) {temp[k++] = a[i++];} else {inv_count += mid - i + 1;temp[k++] = a[j++];}}  // 复制剩余元素while (i <= mid) temp[k++] = a[i++];while (j <= right) temp[k++] = a[j++];    // 将排序结果复制回原数组for (int p = left; p <= right; ++p) a[p] = temp[p];   return inv_count;
}
int main() {const int N = 1e5 + 10;int a[N], temp[N];int n;scanf("%d", &n);   for (int i = 0; i < n; ++i) scanf("%d", &a[i]);   int64_t inv_count = mergeSortAndCount(a, temp, 0, n - 1);cout << inv_count << endl;   return 0;
}

其他方法(使用向量) AI生成

#include <iostream>
#include <vector>using namespace std;
using int64_t = long long;// 合并排序并计数逆序对
int64_t mergeSortAndCount(vector<int>& array, vector<int>& temp, int left, int right) {if (left >= right) return 0;int mid = left + (right - left) / 2;// 递归排序左右两边,并计算逆序对int64_t inv_count = mergeSortAndCount(array, temp, left, mid);inv_count += mergeSortAndCount(array, temp, mid + 1, right);// 合并阶段计算逆序对int i = left, j = mid + 1, k = 0;while (i <= mid && j <= right) {if (array[i] <= array[j]) {temp[k++] = array[i++];} else {inv_count += mid - i + 1; // 计算逆序对temp[k++] = array[j++];}}// 处理剩余元素while (i <= mid) temp[k++] = array[i++];while (j <= right) temp[k++] = array[j++];// 将排序结果复制回原数组copy(temp.begin(), temp.begin() + k, array.begin() + left);return inv_count;
}int main() {int n;cin >> n;vector<int> a(n);for (int& elem : a) cin >> elem;vector<int> temp(n); // 临时数组用于合并cout << mergeSortAndCount(a, temp, 0, n - 1) << endl;return 0;
}
  1. 添加函数注释:解释每个函数的作用,特别是merge_sort中的逻辑。
  2. 使用更明确的变量名:如将q[]改为array[],使代码意图更清晰。
  3. 去除全局变量:尽量减少全局变量的使用,改用函数参数传递。
  4. 优化类型别名的可读性:将LL改为更明确的别名,如typedef long long int64_t;
  5. 使用C++风格的输入输出:完全替换scanfprintfcincout

归并、插入和冒泡排序比较

归并排序

  • 优点:时间复杂度在平均和最坏情况下都为 ,性能比较稳定,适合大规模数据排序。
  • 缺点:需要额外的空间用于合并。

插入排序

  • 优点:对于接近有序的数据表现非常好,在小规模数据或部分有序数据上效率可能较高,代码简单。
  • 缺点:最坏情况时间复杂度为 。

冒泡排序

  • 优点:实现简单。
  • 缺点:时间复杂度较差,也是 。

一般来说,在数据规模较大且对性能要求较高时,归并排序通常表现更好。但如果数据规模较小或者数据有一定的特殊性(如接近有序),插入排序可能更合适。而冒泡排序相对来说在大多数情况下效率较低,较少被优先选用。

使用归并排序解决逆序数对统计问题思路:

在归并排序的合并过程中,当我们比较左右两部分元素时,左边部分一个较大元素如果出现在右边部分较小元素之前,那么就构成一个逆序数对。

当左边当前元素大于右边当前元素时,由于左右两边都是已排序的,那么左边该元素之后的所有元素与右边当前元素都构成逆序数对,数量为左边当前未处理元素的数量。我们可以在合并的同时统计这样的逆序数对数量。通过递归地执行归并排序,不断在合并过程中累加逆序数对的数量,最终就能得到总的逆序数对数量。

例如,假设有数组 [3, 1, 4, 2],在第一次合并 [3] 和 [1] 时,因为 3 大于 1,此时就找到一个逆序数对,然后继续递归合并其他部分并统计。

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

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

相关文章

【数据结构(邓俊辉)学习笔记】图07——最短路径

文章目录 0. 概述1. 问题2. 最短路径2.1 最短路径树2.1.1 单调性2.1.2 歧义性2.1. 3 无环性 2.2 Dijkstra 算法2.2.1 贪心迭代2.2.2 实现2.2.3 实例2.2.4 复杂度 0. 概述 学习下最短路径和Dijistra算法 1. 问题 给定带权网络G (V, E)&#xff0c;以及源点&#xff08;source…

4.大模型微调技术LoRA

大模型低秩适配(LoRA)技术 现有PEFT 方法的局限与挑战 Adapter方法,通过增加模型深度而额外增加了模型推理延时。Prompt Tuning、Prefix Tuning、P-Tuning等方法中的提示较难训练,同时缩短了模型可用的序列长度。往往难以同时实现高效率和高质量,效果通常不及完全微调(f…

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《计及电力不平衡风险的配电网分区协同规划》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

探究IOC容器刷新环节初始化前的预处理

目录 一、IOC容器的刷新环节快速回顾 二、初始化前的预处理prepareRefresh源码分析 三、初始化属性源 &#xff08;一&#xff09;GenericWebApplicationContext初始化属性源 &#xff08;二&#xff09;StaticWebApplicationContext初始化属性源 四、初始化早期事件集合…

3.大模型高效微调PEFT

大模型高效微调(PEFT)技术 预训练模型的背景 预训练与微调:传统的微调方法通常涉及对整个预训练模型的参数进行再训练,以适应特定任务。这虽然有效,但计算成本高,且需要大量的标记数据。模型结构:像BERT或GPT这样的模型通常包含数亿甚至数十亿个参数,构成一个深层次的…

Qt——升级系列(Level Four):控件概述、QWidget 核心属性、按钮类控件

目录 控件概述 QWidget 核心属性 核心属性概览 enabled geometry windowTitle windowIcon windowOpacity cursor font toolTip focusPolicy styleSheet 按钮类控件 Push Button Radio Buttion Check Box Tool Button 控件概述 Widget 是 Qt 中的核⼼概念. 英⽂原义是 "…

西门子学习笔记11 - PTO脉冲指令的使用

1、使用指令前的设置 1、打开一个脉冲发生器&#xff0c;并启用 2、选择使用PTO(脉冲A和方向B) 3、硬件设置输出 4、这样前期的准备工作就完成了 2、指令的使用 1、添加指令CTRL_PTO 2、配置如下 3、方向控制程序如下 4、最后进行测试即可

C语言之存储类、作用域、生命周期、链接属性

一 &#xff1a;概念解析 1&#xff1a; 存储类 &#xff08;1&#xff09;存储类就是存储类型&#xff0c;就是描述C语言变量存储在什么地方 &#xff08;2&#xff09;内存有多种管理方法&#xff1a;栈、堆数据段、bss段、.text段......一个变量的存储类属性就是描述…

html--万年历

<!DOCTYPE html> <html lang"zh_CN"><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8" /><meta charset"utf-8" /><title>万年历</title><link rel"styles…

C语言 | Leetcode C语言题解之第142题环形链表II

题目&#xff1a; 题解&#xff1a; struct ListNode* detectCycle(struct ListNode* head) {struct ListNode *slow head, *fast head;while (fast ! NULL) {slow slow->next;if (fast->next NULL) {return NULL;}fast fast->next->next;if (fast slow) {s…

LLVM Cpu0 新后端9 objdump readelf

想好好熟悉一下llvm开发一个新后端都要干什么&#xff0c;于是参考了老师的系列文章&#xff1a; LLVM 后端实践笔记 代码在这里&#xff08;还没来得及准备&#xff0c;先用网盘暂存一下&#xff09;&#xff1a; 链接: https://pan.baidu.com/s/1yLAtXs9XwtyEzYSlDCSlqw?…

EE trade:如何在A股市场中有效设定止盈止损点

A股市场充满机遇和风险&#xff0c;很多投资者在这里实现了财富增长&#xff0c;也有投资者在这里遭受损失。如何在波动性较大的市场中&#xff0c;控制风险&#xff0c;保护利润和本金?止盈止损是关键。 什么是止盈止损? 止盈止损是指在交易中&#xff0c;根据预先设定的条…

如何稳定高效地进行 TiDB 数据导入导出?

对于在数据库行业中摸爬滚打多年的老鸟 DBA 来说&#xff0c;TiDB 可是一点也不陌生&#xff0c;作为 PingCAP 公司自主研发的真开源分布式数据库&#xff0c;其先进的设计理念以及丰富的生态工具&#xff0c;可算得上是业界自主创新和性能领先的代名词。 TiDB 是谁&#xff1…

MAVEN架构项目管理工具

1、什么是maven Maven是跨平台的项目管理工具。主要服务于基于Java平台的项目构建&#xff0c;依赖管理和项目信息管理。 2、maven的目标&#xff1a;Maven的主要目标是为了使开发人员在最短的时间内领会项目的所有状态 3、使用maven不需要考虑各个依赖的版本&#xff0c;因…

【将xml文件转yolov5训练数据txt标签文件】连classes.txt都可以生成

将xml文件转yolov5训练数据txt标签文件 前言一、代码解析 二、使用方法总结 前言 找遍全网&#xff0c;我觉得写得最详细的就是这个博文⇨将xml文件转yolov5训练数据txt标签文件 虽然我还是没有跑成功。那个正则表达式我不会改QWQ&#xff0c;但是不妨碍我会训练ai。 最终成功…

UE5中在地形中加入湖、河

系统水资产添加 前提步骤123 完成 前提 使用版本 UE5.0.3,使用插件为UE内置的Water和water Extras. 步骤 1 记得重启 2 增加地形&#xff0c;把<启用编辑图层>勾选 如果地形没有勾选上编辑图层&#xff0c;那么就会导致湖、河等水景象无法融入地形。 如果忘记勾选…

Hive知识体系保姆级教程

一. Hive概览 1.1 hive的简介 Hive是基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张数据库表&#xff0c;并提供类SQL查询功能。 其本质是将SQL转换为MapReduce/Spark的任务进行运算&#xff0c;底层由HDFS来提供数据的存储&#xff0c;说白了h…

如何从 Android 图库中恢复误删除的照片

如果您正在阅读这篇文章&#xff0c;那么您肯定意外地从 Android 设备中删除了照片。并且您正在寻找一种简单的方法来恢复 Android 图库中已删除的照片。 从图库恢复已删除的照片 随着技术的进步&#xff0c;现在使用单个设备&#xff08;即 Android 手机&#xff09;&#xf…

使用贝塞尔曲线实现一个iOS时间轴

UI效果 实现的思路 就是通过贝塞尔曲线画出时间轴的圆环的路径&#xff0c;然后 使用CAShaper来渲染UI&#xff0c;再通过 animation.beginTime [cilrclLayer convertTime:CACurrentMediaTime() fromLayer:nil] circleTimeOffset 来设置每个圆环的动画开始时间&#xff0c; …

探索ChatGPT-4在解决化学知识问题上的研究与应用

1. 概述 近年来&#xff0c;人工智能的发展主要集中在 GPT-4 等大型语言模型上。2023 年 3 月发布的这一先进模型展示了利用广泛知识应对从化学研究到日常问题解决等复杂挑战的能力。也开始进行研究&#xff0c;对化学的各个领域&#xff0c;从化学键到有机化学和物理化学&…