归并排序求数组逆序对数

#include <iostream>

using namespace std;

const int LENGTH = 100;
int temp[LENGTH];
int count = 0;

void Merge(int array[], int low, int mid, int high);
void MergeSort(int array[], int low, int high);

/**
 * 合并两个数组[low, mid],(mid, high]到数组[low, high]
 * @param array 待排序数组
 * @param low   起始下标
 * @param mid   分界线
 * @param high  终止下标
 */
void Merge(int array[], int low, int mid, int high)
{
    int tempIndex = low;
    int leftIndex = low;
    int rightIndex = mid + 1;

    while(leftIndex <= mid && rightIndex <= high)
    {
        if(array[leftIndex] < array[rightIndex])
        {
            temp[tempIndex++] = array[leftIndex++];
        }
        else // array[rightIndex]要比[leftIndex, mid]的元素都小,逆序对由此产生
        {
            temp[tempIndex++] = array[rightIndex++];
            count += (mid - leftIndex + 1);
        }
    }

    while(leftIndex <= mid)
    {
        temp[tempIndex++] = array[leftIndex++];
    }

    while(rightIndex <= high)
    {
        temp[tempIndex++] = array[rightIndex++];
    }

    for(int i = low; i <= high; ++i)
    {
        array[i] = temp[i];
    }
}

void MergeSort(int array[], int low, int high)
{
    if(low == high) return;

    int mid = (low + high) / 2;
    MergeSort(array, low, mid);
    MergeSort(array, mid + 1, high);
    Merge(array, low, mid, high);
}

int main()
{
    int array[] = {0, 4, 2, 6, 12, 10, 8, 7, 5};
    MergeSort(array, 0, 8);

    for(auto val : array)
    {
        cout << val << " ";
    }
    cout << endl;
    cout << "--------------------------" << endl;
    cout << count << endl;

    return 0;
}

说明:需要编译器支持C++11

PS C:\Users\Administrator\Desktop\codes> g++ -o .\InverseNumber.exe .\InverseNumber.cpp -std=c++11
PS C:\Users\Administrator\Desktop\codes> .\InverseNumber.exe
0 2 4 5 6 7 8 10 12
--------------------------
12
PS C:\Users\Administrator\Desktop\codes> g++ -v
Using built-in specs.
COLLECT_GCC=F:\GreenSoftware\CodeBlocks\TDM-GCC\bin\g++.exe
COLLECT_LTO_WRAPPER=F:/GreenSoftware/CodeBlocks/TDM-GCC/bin/../libexec/gcc/mingw32/5.1.0/lto-wrapper.exe
Target: mingw32
Configured with: ../../../src/gcc-5.1.0/configure --build=mingw32 --enable-languages=ada,c,c++,fortran,lto,objc,obj-c++
--enable-libgomp --enable-lto --enable-graphite --enable-libstdcxx-debug --enable-threads=posix --enable-version-specifi
c-runtime-libs --enable-fully-dynamic-string --enable-libstdcxx-threads --enable-libstdcxx-time --with-gnu-ld --disable-
werror --disable-nls --disable-win32-registry --disable-symvers --enable-cxx-flags=‘-fno-function-sections -fno-data-sec
tions -DWINPTHREAD_STATIC‘ --prefix=/mingw32tdm --with-local-prefix=/mingw32tdm --with-pkgversion=tdm-1 --enable-sjlj-ex
ceptions --with-bugurl=http://tdm-gcc.tdragon.net/bugs
Thread model: posix
gcc version 5.1.0 (tdm-1)
PS C:\Users\Administrator\Desktop\codes>
时间: 2024-10-08 10:13:24

归并排序求数组逆序对数的相关文章

ACM:归并排序,以及利用归并排序思想求解逆序对数!

(一)归并排序 分析: (1)划分问题:把序列分成元素个数尽量相等的两半. (2)递归求解:把两半元素分别排序. (3)合并问题:把两个有序表合并成一个.(每次只需要把两个序列的最小元素加以比较,删除其中的较小元素并加入合并后的新表) #include <iostream> using namespace std; const int MAXN = 1000; int A[MAXN], T[MAXN]; void merge_sort(int *A, int x, int y, int *T)

POJ 2299 Ultra-QuickSort (树状数组or 归并排序分治求逆序对数)

题目大意就是说帮你给一些(n个)乱序的数,让你求冒泡排序需要交换数的次数(n<=500000) 显然不能直接模拟冒泡排序,其实交换的次数就是序列的逆序对数. 由于数据范围是 0 ≤ a[i] ≤ 999,999,999所以先要离散化,然后用合适的数据结果求出逆序 可以用线段树一步一步添加a[i],每添加前查询前面添加比它的大的有多少个就可以了. 也可用树状数组,由于树状数组求的是(1...x)的数量和所以每次添加前查询i-sum(a[i])即可 树状数组: //5620K 688MS #incl

POJ 2299 Ultra-QuickSort(归并排序求逆序对数)

题目地址:POJ 2299 今天下午的多校看来没有白做...实在做不出题闲着无聊看小白鼠学会了个归并排序.哈哈. 归并排序简单地说其实就是先分成一个二叉树直至单个,然后依次从最底层不断进行合并,逆序对数就是在合并的过程中,加入后面的那段中到了比他大的时候,那后面的那些就都是比他大的,都是逆序对数,所以直接加上即可.网上资料很多,就不细说了..用了分治的思想. 自己根据理解写的代码,考虑的太不全面了..又调了好长时间... 代码如下: #include <algorithm> #include

POJ 2299 Ultra-QuickSort (求序列的逆序对数)

题意:废话了一大堆就是要你去求一个序列冒泡排序所需的交换的次数. 思路:实际上是要你去求一个序列的逆序队数 看案例: 9 1 0 5 4 9后面比它小的的数有4个 1后面有1个 0后面没有 5后面1个 4后面没有 所以结果为4+1+0+1+0=6 所以逆序对的定义如果不清楚可以自己总结了 这道题说白了就是要你用归并排序求逆序对数. 下面是搜到某牛给的逆序对数的方法: 假设回溯到某一步,后面的两部分已经排好序(就是说当前需要归并的两个部分都是分别有序的),假设这两个序列为 序列a1:2 3 5 9

Time Limit Exceeded 求逆序对数。

/** 题目:Time Limit Exceeded 链接:https://oj.ejq.me/problem/28 题意:求逆序对数. 思路:树状数组求逆序对数.维护前面有多少个<=当前数的数的个数. */ #include<bits/stdc++.h> typedef long long ll; using namespace std; const int maxn = 1e6+10; const int mod = 1e9+7; ll c[maxn]; int flag[maxn]

zoj 3157 Weapon 线段树求逆序对数

题目链接:http://www.icpc.moe/onlinejudge/showProblem.do?problemId=3128 题意:平面上有n条直线,给出l, r,求出这些直线的交点横坐标在(l, r)范围内的个数. 思路: 首先求出每条直线与直线x = l和直线x = r的交点,如下图. 因为题目要求区间(l, r)是开区间,所以为了避免交点的横坐标刚好是l或者r的情况,可以先把l加上一个很小的值,r减去一个很小的值,如图中的灰线. 然后求出各条直线与两条灰线的交点,首先按与l的交点的

微软面试题:求一个序列的逆序对数

双层循环排序,时间为O(n2) 归并排序时间为O(nlog(n)) #include<iostream> #include<cstdio> #include<vector> using namespace std; int cnt=0; void merge(vector<int> & nums,int left,int mid,int right); void mergesort(vector<int> & nums,int s

POJ 1840 Brainman(逆序对数)

题目链接:http://poj.org/problem?id=1804 题意:给定一个序列a[],每次只允许交换相邻两个数,最少要交换多少次才能把它变成非递降序列. 思路:题目就是要求逆序对数,我们知道,求逆序对最典型的方法就是树状数组,但是还有一种方法就是Merge_sort(),即归并排序.实际上归并排序的交换次数就是这个数组的逆序对个数,归并排序是将数列a[l,h]分成两半a[l,mid]和a[mid+1,h]分别进行归并排序,然后再将这两半合并起来.在合并的过程中(设l<=i<=mid

求数组逆序对

思路:类似归并排序算法,在合并已经有序的相邻子数组的时候,计算前面数组相对于后面数组的逆序对数,整个递归过程可以算出所有逆序对#include <stdio.h> void merge(int A[], int front, int middle, int end, int &count) { if (front >= end) return; int i = front; int j = middle + 1; int k = 0; int *p = new int[end -