归并排序
百科名片
归并排序
归并排序是建立在归并操作上的一种有效的
排序
算法。该算法是采用
分治法
(Divide and Conquer)的一个非常典型的应用。
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
归并排序是稳定的排序.即相等的元素的顺序不会改变.如输入记录 1(1) 3(2) 2(3) 2(4) 5(5) (括号中是记录的关键字)时输出的 1(1) 2(3) 2(4) 3(2) 5(5) 中的2 和 2 是按输入的顺序.这对要排序数据包含多个信息而要按其中的某一个信息排序,要求其它信息尽量按输入的顺序排列时很重要.这也是它比
快速排序
优势的地方.
编辑本段归并操作
归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。 如 设有数列{6,202,100,301,38,8,1} 初始状态: [6] [202] [100] [301] [38] [8] [1] 比较次数 i=1 [6 202 ] [ 100 301] [ 8 38] [ 1 ] 3 i=2 [ 6 100 202 301 ] [ 1 8 38 ] 4 i=3 [ 1 6 8 38 100 202 301 ] 4 总计: 11次编辑本段算法描述
归并操作的工作原理如下: 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列 设定两个指针,最初位置分别为两个已经排序序列的起始位置 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置 重复步骤3直到某一指针达到序列尾 将另一序列剩下的所有元素直接复制到合并序列尾
与快速排序的比较
归并排序是稳定的排序.即相等的元素的顺序不会改变.如输入记录 1(1) 3(2) 2(3) 2(4) 5(5) (括号中是记录的关键字)时输出的 1(1) 2(3) 2(4) 3(2) 5(5) 中的2 和 2 是按输入的顺序.这对要排序数据包含多个信息而要按其中的某一个信息排序,要求其它信息尽量按输入的顺序排列时很重要.这也是它比
快速排序
优势的地方.
用途
1、排序
(速度仅次于快速排序,但较稳定)2、求逆序对数
具体思路是,在归并的过程中计算每个小区间的逆序对数,进而计算出大区间的逆序对数(也可以用树状数组来求解)ht示例代码
归并排序 归并排序具体工作原理如下(假设序列共有n个元素): 将序列每相邻两个数字进行归并操作(merge),形成floor(n/2)个序列,排序后每个序列包含两个元素 将上述序列再次归并,形成floor(n/4)个序列,每个序列包含四个元素 重复步骤2,直到所有元素排序完毕
归并模板(+ 算逆序数对数)
逆序对,就是诸如 i<j 且 a[i]>a[j] 这样的数对 (i,j)
#include <iostream>
using namespace std;
const int size = 1000;
int invers=0;//求逆序数
int tmpArr[size];//额外空间,用来暂存
void Copy(int a[], int b[], int low, int high)
{
for (int i = low; i <= high; ++i) a[i] = b[i];
}
void Merge(int a[], int b[], int low, int high)
{
int mid = (low + high)/2;
int i, j, k;//i指向[low,mid],j指向[mid+1,high]中的元素
for (i = low, j = mid+1, k = low; i <= mid && j <= high; k++)
{
if (a[i] < a[j]) b[k] = a[i++];//[low,mid]段中的第i个元素a[i]小于 [mid+1,high]段中的a[j],他应该放在前面,所以放入b[]中
else
{
//前面的数大于后面的数,有逆序数
//invers += ??
if (a[i] > a[j])
invers += mid-i+1; //a[i] > a[j], 则a中[i,mid]部分都会大于a[j]
b[k] = a[j++];//只有放入了b[]后,i或j才++
}
}
while (i <= mid) b[k++] = a[i++];
while (j <= high) b[k++] = a[j++];
Copy(a, b, low, high);//将排好序的元素从b中复制给a
}
void MergeSort(int a[], int low, int high)
{
if (low >= high) return ;//递归出口,当区间左值大于等于右值,就不用排序了
int mid = (low + high)/2;//将区间[low,high]分成[low,mid],[mid+1, high]两段分别排序
MergeSort(a, low, mid); //或者分为[low,mid-1]和[mid,high],本程序采用前者
MergeSort(a, mid+1, high);
Merge(a, tmpArr, low, high);//将排好序的 [low,mid],[mid+1, high]两段合并
// Copy(a, tmpArr, low, high);//
}
int main()
{
int arr[size], N, i;
while (cin>>N)
{
invers = 0;
for (i = 0; i < N; ++i)
cin >> arr[i];
MergeSort(arr,0,N-1);
for (i = 0; i < N-1; ++i)
cout << arr[i] << " ";
cout << arr[i] << endl;
cout << "inverse number is " << invers << endl;
}
return 0;
}