時間複雜度:O(n log n)
空間複雜度:O(n)
算法 流程:
設n爲待排序列元素的個數,a[i]爲其中第i個元素,merge_sort爲歸併排序的函數名,b[i]爲兩個相鄰 子序列合併完的臨時有序的序列。
第一步: 將所有的元素 進行二分,直到每個區間 只有一個元素。
然後開始 兩兩區間 進行合併(有序的合併)。
void build(int l,int r)
{
if(l<r)
{
int mid=(l+r)/2;
//printf("%d %d %d---->\n",l,r,mid);
build(l,mid);
//printf("%d %d %d*****\n",l,r,mid);
build(mid+1,r);
//printf("%d %d %d>>>>\n",l,r,mid);
merge_sort(l,mid,r);
}
}
第二步:將已有序的子序列合併(二分到最後的時候,一個元素一定是有序的),得到完全有序的序列
具體代碼:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
int a[500010];
int b[500010];
long long ans;
void merge_sort(int l,int mid,int r)
{
int i=l;//i從l開始的,因爲現在的排序是1~r的區間且要二分合並
int j=mid+1;//j從mid+1開始到r。
int k=l;//數組b的下標,數組b存的是1~r區間排完序的值
while(i<=mid&&j<=r)
{
if(a[i]<=a[j])
b[k++]=a[i++];
else
{
ans+=j-k;
b[k++]=a[j++];
}
}
while(i<=mid) b[k++]=a[i++];//把剩餘的元素存進去
while(j<=r) b[k++]=a[j++];
for(int i=l;i<k;i++)//把有序序列b賦值到a中
a[i]=b[i];
}
void build(int l,int r)
{
if(l<r)
{
int mid=(l+r)/2;
//printf("%d %d %d---->\n",l,r,mid);
build(l,mid);
//printf("%d %d %d*****\n",l,r,mid);
build(mid+1,r);
//printf("%d %d %d>>>>\n",l,r,mid);
merge_sort(l,mid,r);
}
}
int main()
{
int n;
while(~scanf("%d",&n)&&n)
{
ans=0;
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
build(0,n-1);
printf("%lld\n",ans);
}
return 0;
}
模擬過程:(圖解)
>>>>>進行二分
>>>>>進行合併
------------------------------------------------------------------------我是分界線----------------------------------------------------------------------
------------------------------------------------------------------------I am a 分界線----------------------------------------------------------------------
------------------------------------------------------------------************分界線*************--------------------------------------------------------------
------------------------------------------------------------------************分界線*************--------------------------------------------------------------