您的位置:首页 > 编程语言 > C语言/C++

归并排序(C/C++)

2015-08-22 14:45 471 查看

归并排序

算法原理

归并算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。(百度百科)

本文主要实现二路归并。

实质上归并排序就是一个 (不断划分子序列)– (子序列长度为1时停止递归) – (合并子序列) 的过程。

那么如何合并有序子序列?长度为1的子序列当然是有序的。对于长度大于一的序列的合并,我们引用算法导论的扑克的例子,桌上有两堆从小的在上,大的在下的扑克牌,我们要把它们合并为有序的一堆,只需每次把两堆牌顶中小的那张拿下来放在新堆中即可。



复杂度

时间复杂度 O(nlogn)

空间复杂度 O(n)

IO复杂度 (2nlogn)

算法实现

#include <iostream>
#include <cstdio>
#include <cstdlib>
#define LEN 11

using namespace std;

void printarray(int *data,int size)   //打印序列
{
for(int i = 0; i < size ;++i)
{
cout << data[i] << "  " ;
}
cout << endl;
}
void  merge(int *data,int start,int mid,int end)   //排序子序列
{
int ptr = 0;
int origin_mid = mid;
int origin_start = start;   //记录原来的界限
int buffer[end-origin_start+1];
int lenth = end - start +1;
/*  cout << "start:" << start << "  mid:"<<mid << "  end:" << end <<endl;
cout << "Data: ";
printarray(data,11);*/
while(start <= origin_mid || mid <= end)   //当start指针和mid指针均没有越界时,即为两个子序列都不是空序列时循环
{
if ((data[start] < data[mid+1]  || mid >= end ) && start <= origin_mid)
//把前半子序列数据压入缓冲区的情况有  1.前半段头数据较大  2.后半子序列为空 (保证前段不为空)
{
buffer[ptr] = data[start];
start++;    //压入缓冲区,前半段指针后移
ptr++;
}else{
buffer[ptr] = data[mid+1];
mid++;
ptr++;
}
}
/*  cout << "Buffer: ";
printarray(buffer,lenth);*/
for(int i = origin_start; i <= end ;++i)
{
data[i] = buffer[i-origin_start]; //用缓冲区数据代替没有排序的序列
}
/*  cout <<"merged data:";
printarray(data,11);
cout << "----------" << endl;*/
}
void mergesort(int *data,int start,int end) //归并
{
int mid = (start + end )/2;  //分治的分界

if(start < end)
{
mergesort(data,start,mid); //分治
mergesort(data,mid+1,end); //分治
merge(data,start,mid,end); //归并
}
}
int main(int argc, char const *argv[])
{
int data []= {1,5,7,10,2,3,4,8,12,4,13};
mergesort(data,0,LEN-1);
printarray(data,LEN);

return 0;
}


简洁一点的Merge写法:

void Merge(int data[],int start,int mid,int end)
{
int i = start;
int j = mid+1;
int k = start;
int merged_data[LEN];
while(i <= mid && j <= end)//均不为空堆
{
if(data[i]<=data[j])
merged_data[k++]=data[i++];
else
merged_data[k++]=data[j++];
}
while(i <= mid) //后半段为空堆
merged_data[k++]=data[i++];
while(j <= end) //前半段为空堆
merged_data[k++]=data[j++];
for(int l=0 ; l<8 ; l++) //记录数组
data[l]=merged_data[l];
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  归并排序