归并排序算法-OC实现

  • 简介

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

  • 算法描述

第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾

归并排序(Merge Sort)就是利用归并思想对数列进行排序。根据具体的实现,归并排序包括"从上往下"和"从下往上"2种方式

(一、)从上往下

  • C语言实现
/*
 * 将一个数组中的两个相邻有序区间合并成一个
 *
 * 参数说明:
 *     a -- 包含两个有序区间的数组
 *     start -- 第1个有序区间的起始地址。
 *     mid   -- 第1个有序区间的结束地址。
 *     end   -- 第2个有序区间的结束地址。
 */
void merge(int a[], int start, int mid, int end) {
    int *temp = (int *)malloc((end - start + 1) * sizeof(int));    // tmp是汇总2个有序区的临时区域
    int i = start;            // 第1个有序区的起始索引
    int j = mid + 1;        // 第2个有序区的起始索引
    int k = 0;                // 临时区域的索引
    while(i <= mid && j <= end) {
        if (a[i] <= a[j]) {
            temp[k++] = a[i++];
        }else {
            temp[k++] = a[j++];
        }
    }
    
    while(i <= mid) {
        temp[k++] = a[i++];
    }
    while(j <= end) {
        temp[k++] = a[j++];
    }
    // 将排序后的元素,全部都整合到数组a中。
    for (i = 0; i < k; i++) {
        a[start + i] = temp[i];
    }
    free(temp);
}

/*
 * 归并排序(从上往下)
 *
 * 参数说明:
 *     a -- 待排序的数组
 *     start -- 数组的起始地址
 *     endi -- 数组的结束地址
 */
void mergeSortUpToDown(int a[], int start, int end) {
    if(a == NULL || start >= end) {
        return ;
    }
    int mid = (end + start) / 2;
    mergeSortUpToDown(a, start, mid);   //递归排序a[start...mid]
    mergeSortUpToDown(a, mid + 1, end); //递归排序a[mid + 1...end]
    // a[start...mid] 和 a[mid...end]是两个有序空间,
    // 将它们排序成一个有序空间a[start...end]
    merge(a, start, mid, end);
}

//调用
    int a[8] = {50, 10, 20, 30, 70, 40, 80, 60};
    mergeSortUpToDown(a, 0, 7);
    for(i=0; i<8; i++)
        printf("%d ", a[i]);
    printf("\n");
  • OC实现
- (void)mergeWithNumbers:(NSMutableArray *)numbers startIndex:(int)startIndex midIndex:(int)midIndex endIndex:(int)endIndex {
    NSMutableArray *temp = [NSMutableArray array];
    int i = startIndex, j = midIndex + 1, k = 0;
    while (i <= midIndex && j <= endIndex) {
        if ([numbers[i] intValue] <= [numbers[j] intValue]) {
            temp[k++] = numbers[i++];
        }else {
            temp[k++] = numbers[j++];
        }
    }
    while (i <= midIndex) {
        temp[k++] = numbers[i++];
    }
    while (j <= endIndex) {
        temp[k++] = numbers[j++];
    }
    for (int i=0; i < k; i++) {
        numbers[startIndex + i] = temp[i];
    }
    temp = nil;
}

- (void)mergeSortUpToDownWithNumbers:(NSMutableArray *)numbers startIndex:(int)startIndex endIndex:(int)endIndex {
    if (numbers.count == 0 || startIndex >= endIndex) {
        return;
    }
    int midIndex = (startIndex + endIndex) / 2;
    [self mergeSortUpToDownWithNumbers:numbers startIndex:startIndex endIndex:midIndex];
    [self mergeSortUpToDownWithNumbers:numbers startIndex:midIndex + 1 endIndex:endIndex];
    [self mergeWithNumbers:numbers startIndex:startIndex midIndex:midIndex endIndex:endIndex];
}

//调用
NSMutableArray *array = [NSMutableArray arrayWithObjects:@(10),@(4),@(8),@(99),@(16),@(19),@(3), nil];
[self mergeSortUpToDownWithNumbers:array startIndex:0 endIndex:6];
    NSLog(@"%@",array);

(二、)从下往上

  • C语言实现
/*
 * 将一个数组中的两个相邻有序区间合并成一个
 *
 * 参数说明:
 *     a -- 包含两个有序区间的数组
 *     start -- 第1个有序区间的起始地址。
 *     mid   -- 第1个有序区间的结束地址。
 *     end   -- 第2个有序区间的结束地址。
 */
void merge(int a[], int start, int mid, int end) {
    int *temp = (int *)malloc((end - start + 1) * sizeof(int));    // tmp是汇总2个有序区的临时区域
    int i = start;            // 第1个有序区的起始索引
    int j = mid + 1;        // 第2个有序区的起始索引
    int k = 0;                // 临时区域的索引
    while(i <= mid && j <= end) {
        if (a[i] <= a[j]) {
            temp[k++] = a[i++];
        }else {
            temp[k++] = a[j++];
        }
    }
    
    while(i <= mid) {
        temp[k++] = a[i++];
    }
    while(j <= end) {
        temp[k++] = a[j++];
    }
    // 将排序后的元素,全部都整合到数组a中。
    for (i = 0; i < k; i++) {
        a[start + i] = temp[i];
    }
    free(temp);
}

/*
 * 对数组a做若干次合并:数组a的总长度为len,将它分为若干个长度为gap的子数组;
 * 将"每两个相邻的子数组" 进行合并排序。
 *
 * 参数说明:
 *     a -- 待排序的数组
 *     len -- 数组的长度
 *     gap -- 子数组的长度
 */
void mergeGroups(int a[], int len, int gap) {
    int i;
    int doubleLen = 2 * gap;    // 两个相邻的子数组的长度
    // 将"每2个相邻的子数组" 进行合并排序。
    for(i = 0; i + doubleLen - 1 < len; i += (doubleLen)) {
        merge(a, i, i + gap - 1, i + doubleLen - 1);
    }
    // 若 i + gap - 1 < len - 1,则剩余一个子数组没有配对。
    // 将该子数组合并到已排序的数组中。
    if (i + gap - 1 < len - 1) {
        merge(a, i, i + gap - 1, len - 1);
    }
}

/*
 * 归并排序(从下往上)
 *
 * 参数说明:
 *     a -- 待排序的数组
 *     len -- 数组的长度
 */
void mergeSortDownToUp(int a[], int len) {
    int n;
    if (a == NULL || len <= 0) {
        return ;
    }
    for(n = 1; n < len; n *= 2) {
        mergeGroups(a, len, n);
    }
}

//调用
    int a[8] = {50, 10, 20, 30, 70, 40, 80, 60};
    mergeSortDownToUp(a, 8);
    for(i=0; i<8; i++)
        printf("%d ", a[i]);
    printf("\n");
  • OC实现
- (void)mergeWithNumbers:(NSMutableArray *)numbers startIndex:(int)startIndex midIndex:(int)midIndex endIndex:(int)endIndex {
    NSMutableArray *temp = [NSMutableArray array];
    int i = startIndex, j = midIndex + 1, k = 0;
    while (i <= midIndex && j <= endIndex) {
        if ([numbers[i] intValue] <= [numbers[j] intValue]) {
            temp[k++] = numbers[i++];
        }else {
            temp[k++] = numbers[j++];
        }
    }
    while (i <= midIndex) {
        temp[k++] = numbers[i++];
    }
    while (j <= endIndex) {
        temp[k++] = numbers[j++];
    }
    for (int i=0; i < k; i++) {
        numbers[startIndex + i] = temp[i];
    }
    temp = nil;
}

- (void)mergeGroupWithNumbers:(NSMutableArray *)numbers length:(int)length gap:(int)gap {
    int i;
    int doubleLen = gap * 2;
    for (i=0; i + doubleLen - 1 < length; i += (doubleLen)) {
        [self mergeWithNumbers:numbers startIndex:i midIndex:i + gap - 1 endIndex:i + doubleLen - 1];
    }
    if (i + gap - 1 < length - 1) {
        [self mergeWithNumbers:numbers startIndex:i midIndex:i + gap - 1 endIndex:length - 1];
    }
}

- (void)mergeSortDownToUpWithNumbers:(NSMutableArray *)numbers length:(int)length {
    if (numbers.count == 0 || length <= 0) {
        return;
    }
    for (int n=1; n < length; n *= 2) {
        [self mergeGroupWithNumbers:numbers length:length gap:n];
    }
}

//调用
NSMutableArray *array = [NSMutableArray arrayWithObjects:@(10),@(4),@(8),@(99),@(16),@(19),@(3), nil];
[self mergeSortDownToUpWithNumbers:array length:7];
    NSLog(@"%@",array);
  • 时间复杂度

最好、最坏和平均时间复杂度均为O(nlogn)。

  • 算法稳定性

是一种稳定算法

你可能感兴趣的:(归并排序算法-OC实现)