Merge sorting idea is to sort small parts (pairs) than longer (4 items) and etc, but each next sort phase is MERGE of previous sorted parts. Merging of 2 sorted parts should saves order of items:
1,5 merging 2,3 is 1,2,3,5.
If we avoid recursive implementation then we should generate indexes of all parts (2 items, 4 items...). This sub-task will be done in mergesort() function. Another sub-task is to merge 2 sorted parts into new one, but sorted too. This is implemented in _merge() function, which avoid additional array of result by using of swapping of items: we has 2 arrays with 2 indexes and compare both items (from one array and another, indexed by these 2 indexes). If they need reordering then we swap items. Index of lesser item is incremented (see code below).Main problem is to calculate middle index (for splitting input array into 2 parts for merging). Next formula is used:
mid = lev*2 + pielen*pie;
if (pielen > len || mid > len-1) mid = lastleft;
where lev is the level of pseudo-recursion, pielen is the length of pie (part) = {2, 4, 8...}. len is the length of input array, lastleft is the index of left bound of previous "level". So, we should to get something like this:lev=0 left=0 mid=0 right=2
lev=0 left=2 mid=2 right=4
lev=0 left=4 mid=4 right=6
lev=0 left=6 mid=6 right=8
lev=0 left=8 mid=8 right=10
lev=0 left=10 mid=10 right=12
lev=1 left=0 mid=2 right=4
lev=1 left=4 mid=6 right=8
lev=1 left=8 mid=10 right=12
lev=2 left=0 mid=4 right=8
lev=2 left=8 mid=8 right=12
lev=3 left=0 mid=8 right=12
So, this is the code:
#include <stdio.h> #include "algutils.h" template<typename> static inline void _merge(T *arr, int left, int mid, int right) { T tmp, // tmp item needed for inserting if head position on shift *larr, // left subarray *rarr; // right subarray int llen, // length of left subarray rlen; // length of right subarray int l, r; // indexes of compared items in left, right subarrays l = r = 0; larr = &arr[left]; if (mid==left) { // When len==2 swapping is more preferable rarr = &arr[mid+1]; llen = mid - left + 1; rlen = right - mid - 1; } else { // Common case rarr = &arr[mid]; llen = mid - left; rlen = right - mid; } // Index in left subarray is limited by "right" index while ((larr+l < rarr+r) && r < rlen) { if (larr[l] > rarr[r]) { tmp = rarr[r]; RSHIFT_ARR(larr+l, llen-(l-r), 1); larr[l] = tmp; r++; } l++; } } template<typename> int mergsort(T* arr, int len) { int lev, // level of "recursion" pie, // number of subarray (of part) pielen, // subarray length: 2, 4, 8... left, right, // bounds (right is not included) mid, // middle point for splitting - is the same as left bound of subarray but on prev. level lastleft; // last left index if (!arr||!len) return (0); lev = 0; pielen = 2; while (pielen < 2*len) { pie = 0; do { left = pie*pielen; right = left + pielen; if (right > len) right = len; mid = lev*2 + pielen*pie; if (pielen > len || mid > len-1) mid = lastleft; //mid = len-2; _merge(arr, left, mid, right); pie++; } while (right < len-1); pielen *= 2; lev++; lastleft = left; } return (1); } /***************************************** main ****************************************/ int main(void) { int arr1[] = {10, 19, 1, 2, 10, 450, 6, 7, 8, 100, 120, 121}; mergsort(arr1, sizeofarray(arr1)); PRINTARR(arr1, "%d"); return (0); }Macros RSHIFT_ARR() is trivial:
/// Shift array @a ARR of length @a LEN by @a N positions to right #define RSHIFT_ARR(ARR, LEN, N) do { \ register int _rshift_arr_i_; \ for (_rshift_arr_i_=(N)+(LEN)-1; \ _rshift_arr_i_>(N)-1; \ _rshift_arr_i_--) \ { \ *((ARR)+_rshift_arr_i_) = *((ARR)+(_rshift_arr_i_-(N))); \ } \ } while (0)
Комментариев нет:
Отправить комментарий
Thanks for your posting!