使用快排和归并求解逆序对

本文介绍了如何使用归并法和快排法计算给定文件中100,000个随机整数的逆序对数量。归并法通过有序合并子数组来计算,快排法利用分治策略,选取轴值并重新排列数组以计算逆序对。两种方法的时间复杂度均为O(nlogn),文章中还包含了实际运行时间的比较。" 115742640,10762756,病人排队算法实现,"['python', '排序算法']

The attached file Q8.txt contains 100,000 integers between 1 and 100,000 (each row has a single integer), the order of these integers is random and no integer is repeated.

  1. Write a program to implement the Sort-and-Count algorithms in your favorite language, find the number of inversions in the given file.
  2. In the lecture, we count the number of inversions in O(nlogn) time, using the Merge-Sort idea. Is it possible to use the Quick-Sort idea instead ?

If possible, implement the algorithm in your favourite language, run it over the given file, and compare its running time with the one above. If not, give a explanation



1. 归并法


最终逆序对的个数是:2500572073

这里写图片描述

归并法的核心就是通过讲子问题划分成一个一个小的问题后进行合并求解。首先对整个数组一直对半的进行划分,一直分到只剩1个为止开始排序并合并,如上图所示。

具体算法如下。从第74行开始计算将要合并的两个子数组的逆序对数,如果左边数组的的一个值是大于右边数组中的数的,则说明左边数组中这个数的后面所有的数字都是大于右边数组的这个数字的(因为在合并时,左右两边数组都已经是有序的),因此直接加 (mid - left + 1 - i) 就可以了,然后一层一层的向上计算过去,即得到了逆序对数。

因为老师有让对比归并法和快排法的效率,因此中间有计算时间的。


#include<cstdio>
#include<cstdlib>
#include<string.h> 
#include<sys/time.h>
#include<iostream>
#include<fstream>
#define MAXN 100001
using namespace std;

double SortAndCount(int left, int right);
double MergeAndCount(int left, int mid, int mid1, int right);

//int num[] = {2, 4, 1, 3, 5};
//int num[] = {4, 7, 6, 3, 1, 2, 9, 8, 5};
int num[MAXN];

int main()
{
    char n[15];
    int i = 0;
    double ans;
    struct timeval t_start, t_end;

    //open the file 
    ifstream in("Q8.txt", ios::in);
    
<think>嗯,用户这次问的是算法排序能解决哪些实际问题。从对话历史看,用户之前接触过排序算法的分类性能对比(引用13),也了解排序是基础算法(引用2)。不过用户现在更关注应用层面,需要具体例子而非理论。 用户可能正在准备面试(引用1提到"面试常考算法题"),或者想理解算法的实际价值。ta的提问方式比较开放,说明需要系统性的应用场景梳理。考虑到之前讨论过快速排序,可以强调分治思想在非排序问题中的应用。 关于排序的应用,除了直接整理数据外,重点要突出三个维度: 1. 基础功能类:搜索优化、数据去重这些直接依赖有序性的场景; 2. 衍生问题类:比如逆序对计算本质是把"比较"转化为计数问题; 3. 思想迁移类:像快速选择算法借用partition思想解决topK问题。 特别要注意引用3提到的工程实践倾向——虽然理论上有很多排序算法,但实际工程中更多用快排/归并/堆排序。在回答应用案例时需要呼应这点,比如数据库索引通常用B树而非桶排序。 用户可能会追问某个具体场景的实现细节,所以提前准备相关问题:比如"海量数据排序"涉及外部排序,"稳定性要"涉及归并排序的选择等。这样既解答当前问题,又预判了后续需。 </think>排序算法及其底层思想能解决的核心问题远超数据整理本身,以下按应用场景分类说明: --- ### 一、基础数据操作类问题 1. **高效检索** - 有序数据可使二分查找时间复杂度降至 $O(\log n)$ - 应用场景:数据库索引、字典检索、拼写检查[^3] 2. **数据去重与统计** ```python # 排序后去重示例 def remove_duplicates(arr): arr.sort() # 先排序 return [arr[i] for i in range(len(arr)) if i==0 or arr[i]!=arr[i-1]] ``` 3. **极值筛选** - 快速选择算法(基于快排思想)可在 $O(n)$ 时间内找出第K大元素[^1] --- ### 二、复杂问题建模类问题 1. **逆序对问题** - 通过修改归并排序,在 $O(n \log n)$ 时间内计算逆序对数量 - 应用场景:股票分析、推荐系统冷启动[^1][^3] ``` 逆序对计算公式: 在归并过程中若 arr[i] > arr[j],则逆序对增加 mid - i + 1 ``` 2. **小问题** - 计算每个元素左侧小于它的元素总 - 归并排序过程中同步累加小[^1] 3. **区间合并** ```python # 排序解决区间合并问题 def merge_intervals(intervals): intervals.sort(key=lambda x: x[0]) # 按起点排序 merged = [] for interval in intervals: if not merged or merged[-1][1] < interval[0]: merged.append(interval) else: merged[-1][1] = max(merged[-1][1], interval[1]) return merged ``` --- ### 三、系统级优化问题 1. **负载均衡** - 桶排序思想用于分布式系统中的数据分片 - 例:Cassandra数据库的Token分区机制[^2] 2. **任务调度** - 堆排序(优先级队列)实现高效任务调度 - 应用场景:操作系统进程调度、定时器系统 3. **内存管理** - 内存分配器使用排序思想管理空闲内存块 - 最佳适应算法需按块大小排序[^3] --- ### 四、数学与几何问题 1. **最近点对问题** - 分治法结合按坐标排序,在 $O(n \log n)$ 求解平面最近点对 2. **凸包构建** ```python # Graham扫描法(依赖极角排序) def convex_hull(points): points.sort(key=lambda p: (p.x, p.y)) # 先按坐标排序 # ... 后续极角排序处理 ``` 3. **线性插值与拟合** - 数据排序是多项式拟合的前置步骤 --- ### 五、数据工程问题 1. **外部排序(海量数据)** - 归并排序思想处理超出内存的数据集 - MapReduce中的Shuffle阶段本质是分布式归并[^2] 2. **基数排序优化** - 处理电话号码、IP地址等定长字符串排序 - 时间复杂度 $O(nk)$(k为字符串长度) --- ‡‡ 相关问题 ‡‡ 1. 如何证明基于比较的排序算法时间复杂度下界为 $Ω(n \log n)$? 2. 在解决逆序对问题时,归并排序比冒泡排序高效的根本原因是什么? 3. 现代数据库如何利用B+树结构同时优化排序与检索? 4. 桶排序在什么场景下能达到 $O(n)$ 时间复杂度?其限制条件是什么? > 参考资料揭示的核心洞见:**排序不仅是整理数据的手段,更是分治、贪心、递归等算法思想的载体**。实际应用中需综合考虑时间复杂度、空间复杂度、稳定性三大维度,这也是快排/归并/堆排序成为工程主流的原因[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值