归并排序 --- 排序算法4

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

归并排序, 每次的小循环和合并2个有序链表有点类似.

     1.把原始数组看成n个小数组组成的,每个小数组都是有序的,

     2.相邻的2个数字合并成一个有序数组,

     3.相邻的4个数字合并成一个有序数组,

     ....

     最后所有数字合并变成一个有序数组.

- (void)sortAction {
    /*
     归并排序,和合并2个有序链表有点类似
     1.把原始数组看成n个,每个数字都看成有序的,
     2.相邻的2个数字合并成一个有序数组,
     3.相邻的4个数字合并成一个有序数组,
     ....
     最后所有数字合并变成一个有序数组
     */
    const int num = 50000;
    int a[num];

    for (int i = 0; i<num; i++) {
        a[i] = arc4random()%(num*10);
    }
    
    
    
    // 存放暂时的合并结果
    int result[num];
    memset(result, 0, sizeof(int)*num);
    int step = 1;
    while (step<=num) {
        
        // 把a数组按照step分割,每个step内部是有序的,结果放到result中
        [self mergeArray:a toTargetArray:result step:step count:num];
        step *= 2;
        // 如果此时step>num, 说明result中的已经是排好序的了, 再次调用,把result的结果复刻一份到原始数组
        [self mergeArray:result toTargetArray:a step:step count:num];
        step *= 2;
    }
    
    
    for (int i = 0; i<num; i++) {
        printf("%d -> ",a[i]);
    }
    printf("排序完成\n");
    
}

/// 把a数组按照step分割,每个step内部是有序的,结果放到result中
- (void)mergeArray:(int [])a toTargetArray:(int [])result step:(int)step count:(int)count {
    
    
    int i = 0;
    // 处理完整的step分组,保证最右边的数字不越界
    for (; i+2*step<=count; i+=step*2) {
        
        /// 把数组a中[start,mid) 和 [mid,end) 构成的2个有序数组合并成一个有序数组放到result的[start,end)中
        [self __mergeArray:a toTargetArray:result form:i mid:i+step end:i+2*step];
    }
    
    // 到这里说明前面的完整组合并完成了, 还剩最后一个尾巴, 尾巴的长度可能是一个完整组,可能不到一个组
    if (i+step<count) {
        // 还有一个完整的一组, 一个半组, 进行合并成一个组
        [self __mergeArray:a toTargetArray:result form:i mid:i+step end:count];
    } else {
        // 剩下的不够完整的一步了
        for (; i<count; i++) {
            result[i] = a[i];
        }
    }
    
 
}


/// 把数组a中[start,mid) 和 [mid,end) 构成的2个有序数组合并成一个有序数组放到result的[start,end)中
- (void)__mergeArray:(int [])a toTargetArray:(int [])result form:(int)start mid:(int)mid end:(int)end {
    
    int i = start; //[start,mid) 的下标
    int j = mid; // [mid,end) 的下标
    int r = start; //result的下标
    while (i<mid && j<end) {
        
        if (a[i] <= a[j]) {
            result[r] = a[i];
            i++;
        } else {
            result[r] = a[j];
            j++;
        }
        r++;
        
    }
    // 到这里说明有一个队列走到了尽头, 不管是哪个队列,都把另一个队列的后续元素追加到result中
    for (; i<mid; i++) {
        result[r] = a[i];
        r++;
    }
    for (; j<end; j++) {
        result[r] = a[j];
        r++;
    }
    
}

时间复杂度是, 每次的step是*2的, 需要logN次step的循环,  内循环把2个有序数组合并成一个,需要执行N次, 所以2者相乘, 最终的时间复杂度是O(NLogN).  目前来看效率最好的了.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值