MergeSort归并排序递归、迭代、原地 c++实现

来源:互联网 发布:oracl 显示所有数据库 编辑:程序博客网 时间:2024/06/05 09:39

分治(Divide and Conquer)的思想,平均、最好、最坏,时间效率都是O(n log n)。
有递归和迭代两种实现方法。对于顺序存储如数组,一般为O(n)的空间;list的空间直接为O(1)。
空间上可以使用原地归并避免O(n)的空间。但较麻烦,且需要多次移动,除非有特殊说明或空间非常宝贵,否则不建议原地归并。

void merge_sort(vector<int>& arr){    if(arr.empty()) return;    vector<int> ans(arr.size());    merge_sort_re(arr, ans, 0, arr.size());//1.递归    //merge_sort_it(arr, arr.size());//2.迭代}

1.递归

void merge_sort_re(vector<int>& arr, vector<int>& ans, int beg, int end){    if(end - beg <= 1)return;    int mid = beg + (end-beg)/2;    merge_sort_re(arr, ans, beg, mid);    merge_sort_re(arr, ans, mid, end);    merge(arr, ans, beg, end);//a.归并, O(n)的空间    //merge_inplace(arr, beg, end);//b.原地归并, O(1)的空间}

a.归并, O(n)的空间

void merge(vector<int>& arr, vector<int>& ans, int beg, int end){    int mid = beg + (end-beg)/2;    int i = beg, j = mid, k = beg;    while(i<mid && j<end) ans[k++] = arr[i]>arr[j] ? arr[j++] : arr[i++];    while(i<mid) ans[k++] = arr[i++];    while(j<end) ans[k++] = arr[j++];    for(k = beg; k<end; ++k) arr[k] = ans[k];}

b. 原地归并, O(1)的空间

merge_inplace(arr, beg, end),归并[beg,end)范围内的数。其中,[beg,mid)、[mid,end)分别有序。
算法流程:
(0)变量i、j初值分别为beg、mid = beg + (end-beg)/2。
(1)首先自增i,在arr前半部找到第一个比arr[j]大的数,为arr[i];
中间变量k保存此时j的值;
(2)然后自增j,在arr后半部找到第一个比arr[i]大的数,为arr[j];
(3)此时,arr[i]前的数不需要处理;arr[x] (x的范围为[i,k) )中的全部数(记为A_x)大于arr[y](y的范围为[k,j) )中的全部数(记为A_y);记移动前,t = arr[j],现在只需要通过 move(arr, i, k, j) 将A_y 中的全部数移至A_x中的全部数前,即可保证arr在[beg, end)范围内,移动后数t所在的位置之前(不包括数t所在的位置)的全部数都有序;
(3)更新i的值为移动后arr[i]所在位置,即i自增区间[k,j)的长度 i+=j-k,重新执行(1)~(3),直到i、j满足循环退出条件。

时间分析:最坏O(n^2),因此除非有特殊说明或空间非常宝贵,否则不建议原地归并。

//将arr中[k,j)范围内的数移至[i,k)范围前void move(vector<int>& arr, int i, int k, int j){    reverse(arr.begin()+i, arr.begin()+k);    reverse(arr.begin()+k, arr.begin()+j);    reverse(arr.begin()+i, arr.begin()+j);}//原地归并, O(1)的空间void merge_inplace(vector<int>& arr, int beg, int end){    int mid = beg + (end-beg)/2;    int i = beg, j = mid;    while(i<j && j<end){        int k = j;        while(i<j && arr[i]<=arr[j]) ++i;        while(j<end && arr[j]<=arr[i]) ++j;        move(arr, i, k, j);        i+=j-k;    }}

reference: blog

2.迭代

void merge_sort_it(vector<int>& arr, int len){    vector<int> ans(len);    for(int seg = 1; seg < len; seg+=seg){        for(int beg = 0; beg < len; beg+=seg+seg){            int low = beg, mid = std::min(beg+seg, len), high = std::min(beg+seg+seg, len);            int i = low, j = mid, k = low;            while(i<mid && j < high) ans[k++] = arr[i]>arr[j] ? arr[j++] : arr[i++];            while(i<mid) ans[k++] = arr[i++];            while(j<high) ans[k++] = arr[j++];            for(k = beg; k < high; ++k) arr[k] = ans[k];        }    }}

reference: wiki


阅读全文
0 0
原创粉丝点击