zoukankan      html  css  js  c++  java
  • 算法之路

    归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。分治法就是将一个大问题分解成小问题然后递归求解,然后再将小问题的结果合并,最终得到问题的解。

    归并操作

    归并操作,也叫归并算法,指的是将两个有序的序列合并成一个有序的序列的方法。

    算法描述

    归并操作的工作原理如下:

    第一步:申请空间,使其大小为两个有序序列之和,该空间用来存放合并后的序列。

    第二步:设定两个指针,初始位置分别为两个有序列表的起始位置。

    第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间(即之前申请的空间内),并移动指针到下一位置。

    重复步骤3,知道某一指针超过序列尾。

    最后,将另一序列剩下的元素直接复制到合并序列的尾部。

    稳定性

    归并排序是稳定的排序,即相等的元素的顺序不会改变。归并排序的比较次数小于快速排序的比较次数,但是移动次数一般多余快速排序的移动次数。一般用于总体无序,但是各子项相对有序的序列。

    归并排序的OC实现

    归并排序又分为自上而下和自下而上两种方式。

    • 自上而下,就是利用递归(或者迭代)将目标序列先拆分成两个小序列,然后对小序列再分别执行归并排序,以此类推直到小序列中只有一个元素,然后开始合并小序列。
    • 自下而上,就是直接从目标序列中,将两个相邻的元素两两归并,分别得到归并后的序列,再进行两两归并,直到最后只有一个序列,即为排序完成后的序列。

    因为归并排序是比较好理解的一种排序算法,所以不做过多赘述,直接来看实现吧。

    自上而下的归并排序:

    /**
     归并排序(自上而下)
     
     @param randomNumbers 随机数组
     @return 排序后的数组
     */
    + (NSMutableArray *)mergeSort:(NSMutableArray *)randomNumbers
    {
        if (randomNumbers.count <= 1) {
            return randomNumbers;
        }
        
        if (![randomNumbers isKindOfClass:[NSMutableArray class]]) {
            NSLog(@"参数类型错误,请使用NSMutableArray类型对象做入参");
            return nil;
        }
        
        // 创建一个临时数组,以防递归过程中频繁创建数组耗时
        NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:randomNumbers.count];
        
        [self sort:randomNumbers low:0 high:(int)randomNumbers.count-1 tempArray:tempArray];
        
        return randomNumbers;
    }
    
    + (void)sort:(NSMutableArray *)randomNumbers low:(int)low high:(int)high tempArray:(NSMutableArray *)tempArray
    {
        if (high <= low) {
            ret 大专栏  算法之路urn ;
        }
        
        int mid = low + (high - low) / 2;
        
        [self sort:randomNumbers low:low high:mid tempArray:tempArray];
        [self sort:randomNumbers low:mid + 1 high:high tempArray:tempArray];
        [self merge:randomNumbers low:low mid:mid high:high tempArray:tempArray];
    }
    
    + (void)merge:(NSMutableArray *)randomNumbers low:(int)low mid:(int)mid high:(int)high tempArray:(NSMutableArray *)aux
    {
        int i = low;
        int j = mid + 1;
        // 先将数据存到临时数组中
        for (int z = low; z <= high; z++) {
            aux[z] = randomNumbers[z];
        }
        
        for (int k = low; k <= high; k++) {
            if (i > mid) {
                // 说明左子序列的元素都已用完
                randomNumbers[k] = aux[j++];
            } else if (j > high) {
                // 说明右子序列的元素都已用完
                randomNumbers[k] = aux[i++];
            } else if ([aux[i] intValue] < [aux[j] intValue]) {
                randomNumbers[k] = aux[i++];
            } else {
                randomNumbers[k] = aux[j++];
            }
        }
    }
    
    

    而自下而上的归并排序是这样的:

    /**
     归并排序(自下而上)
     
     @param randomNumbers 随机数组
     @return 排序后的数组
     */
    + (NSMutableArray *)mergeSort2:(NSMutableArray *)randomNumbers
    {
        if (randomNumbers.count <= 1) {
            return randomNumbers;
        }
        
        if (![randomNumbers isKindOfClass:[NSMutableArray class]]) {
            NSLog(@"参数类型错误,请使用NSMutableArray类型对象做入参");
            return nil;
        }
        
        int count = (int)randomNumbers.count;
        NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:randomNumbers.count];
        for (int sz = 1; sz < count; sz = sz + sz) {
            for (int lo = 0; lo < count - sz; lo += (sz + sz)) {
                // 让前两个序列归并,因为一个序列有sz个元素,所以中间元素是lo+sz-1,最大的元素是lo+sz+sz-1。
                // 为了防止越界,high 要去 lo + sz + sz -1 与 count -1中较小的元素
                int high = MIN(lo + sz + sz - 1, count - 1);
                [self merge:randomNumbers low:lo mid:lo + sz - 1 high:high tempArray:tempArray];
            }
        }
        
        return randomNumbers;
    }
    
    + (void)merge:(NSMutableArray *)randomNumbers low:(int)low mid:(int)mid high:(int)high tempArray:(NSMutableArray *)aux
    {
        int i = low;
        int j = mid + 1;
        // 先将数据存到临时数组中
        for (int z = low; z <= high; z++) {
            aux[z] = randomNumbers[z];
        }
        
        for (int k = low; k <= high; k++) {
            if (i > mid) {
                // 说明左子序列的元素都已用完
                randomNumbers[k] = aux[j++];
            } else if (j > high) {
                // 说明右子序列的元素都已用完
                randomNumbers[k] = aux[i++];
            } else if ([aux[i] intValue] < [aux[j] intValue]) {
                randomNumbers[k] = aux[i++];
            } else {
                randomNumbers[k] = aux[j++];
            }
        }
    }
    

    Have Fun!


  • 相关阅读:
    作业呢
    留言板
    题解 lg2480 古代猪文
    题解 lg4139 上帝与集合的正确用法
    AFO
    题解 lg2946 [USACO09MAR]Cow Frisbee Team S
    题解 lg4158 [SCOI2009]粉刷匠
    题解 HDU4035 Maze
    题解 lg3232 [HNOI2013]游走
    题解 HDU4652 Dice
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12401879.html
Copyright © 2011-2022 走看看