排序算法

2021-05-20  本文已影响0人  Silence_xl
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSArray (Sort)

/**
 * 插入排序
 *
 * 是否基于比较:是
 * 是否稳定排序:是
 * 是否原地操作:是
 * 时间复杂度为O(n2),比较高,适合小规模数据的排序。
 * 适合排序数据类型:NSString,NSNumber,CGFloat,NSInteger,long
 **/
- (void)insertionSortArray:(NSMutableArray *)array;

/**
 * 选择排序
 *
 * 是否基于比较:是
 * 是否稳定排序:否
 * 是否原地操作:是
 * 时间复杂度为O(n2),比较高,适合小规模数据的排序。
 * 适合排序数据类型:NSString,NSNumber,CGFloat,NSInteger,long
 **/
- (void)selectSortArray:(NSMutableArray *)array;

/**
 * 冒泡排序
 *
 * 是否基于比较:是
 * 是否稳定排序:是
 * 是否原地操作:是
 * 时间复杂度为O(n2),比较高,适合小规模数据的排序。
 * 适合排序数据类型:NSString,NSNumber,CGFloat,NSInteger,long
 **/
- (void)bubbleSortArray:(NSMutableArray *)array;

/**
 * 快速排序
 *
 * 是否基于比较:是
 * 是否稳定排序:否
 * 是否原地操作:是
 * 时间复杂度为O(nlogn),因此大规模表现良好。
 * 适合排序数据类型:NSString,NSNumber,CGFloat,NSInteger,long
 **/
- (void)quickSortArray:(NSMutableArray *)array withLeftIndex:(NSInteger)leftIndex andRightIndex:(NSInteger)rightIndex;

/**
 * 希尔排序
 *
 * 是否基于比较:是
 * 是否稳定排序:是
 * 是否原地操作:是
 * 时间复杂度为O(n(1.3—2)),因此中等大小规模表现良好。
 * 适合排序数据类型:NSString,NSNumber,CGFloat,NSInteger,long
 **/
- (void)shellSortArray:(NSMutableArray *)array;

//堆排序
- (void)heapSortArray:(NSMutableArray *)array;

/**
 * 归并排序
 *
 * 是否基于比较:是
 * 是否稳定排序:是
 * 是否原地操作:否
 * 时间复杂度为O(nlogn),因此大规模表现良好。
 * 适合排序数据类型:NSString,NSNumber,CGFloat,NSInteger,long
 **/
- (void)megerSortAscendingOrderSort:(NSMutableArray *)ascendingArray;

/**
 * 基数排序
 *
 * 是否基于比较:否(线性排序)
 * 是否稳定排序:是
 * 是否原地操作:否
 * 时间复杂度为更低的O(n),但是对要排序的数据要求很苛刻,基数排序要求数据可以划分成高低位,位之间有递进关系。比较两个数,我们只需要比较高位,高位相同的再比较低位。而且每一-位的数据范围不能太大。
 * 适合排序数据类型:NSString,NSNumber,NSInteger,long
 **/
- (void)radixSortArray:(NSMutableArray *)array;



/**
 * 二分查找(循环)
 **/
- (NSInteger)binarySearch:(NSArray *)source target:(NSInteger)target;

@end

NS_ASSUME_NONNULL_END

#import "NSArray+Sort.h"

@implementation NSArray (Sort)

#pragma mark 插入排序
/**
 * 插入排序
 *
 * 是否基于比较:是
 * 是否稳定排序:是
 * 是否原地操作:是
 * 时间复杂度为O(n2),比较高,适合小规模数据的排序。
 * 适合排序数据类型:NSString,NSNumber,CGFloat,NSInteger,long
 **/
- (void)insertionSortArray:(NSMutableArray *)array {
    for (int i = 1; i < array.count; i++) {
        int j = i;  /* j是一个坑, 确定坑的位置,再把数从坑里取出来,注意顺序*/
        id temp = array[i]; /* temp 是从坑里取数*/
        if ([array[i] intValue] < [array[i-1] intValue]) {  /* j > 0 防止越界。写&&前面效率更高*/
            while (j > 0 && [temp intValue] < [array[j-1] intValue]) {
                array[j] = array[j-1];
                j--;
            }
            array[j] = temp;
        }
    }
    NSLog(@"%@",array);
}

#pragma mark 选择排序 --每次把最大的选出来 放到前面,然后依次类推
/**
 * 选择排序
 *
 * 是否基于比较:是
 * 是否稳定排序:否
 * 是否原地操作:是
 * 时间复杂度为O(n2),比较高,适合小规模数据的排序。
 * 适合排序数据类型:NSString,NSNumber,CGFloat,NSInteger,long
 **/
- (void)selectSortArray:(NSMutableArray *)array {
    int index = 0;//记录找到的关键字下标
    for (int i = 0; i < array.count - 1; i++) {
        index = i;
        for (int j = i + 1; j < array.count; j++) {
            if ([array[index] integerValue] < [array[j]integerValue]) {
                //如果有比当前index值大的值,则记录次下标
                index = j;//记录最大值(最小值)的下标
            }
        }
        if (i != index) {  //若index不等于i,说明找到最大值,交换
            [array exchangeObjectAtIndex:i withObjectAtIndex:index];
        }
    }
    NSLog(@"%@",array);
}

#pragma mark 冒泡排序
/**
 * 冒泡排序
 *
 * 是否基于比较:是
 * 是否稳定排序:是
 * 是否原地操作:是
 * 时间复杂度为O(n2),比较高,适合小规模数据的排序。
 * 适合排序数据类型:NSString,NSNumber,CGFloat,NSInteger,long
 **/
- (void)bubbleSortArray:(NSMutableArray *)array {
    for (NSInteger i = 0; i < array.count-1; i++) {
        for (NSInteger j = 0; j < array.count-1-i; j++) {
            NSInteger left = [array[j] integerValue];
            NSInteger right = [array[j+1] integerValue];
            if (left > right) {
                [array exchangeObjectAtIndex:j withObjectAtIndex:j+1];
            }
        }
    }
    NSLog(@"%@",array);
}

#pragma mark 快速排序
//1. 算法思想
//快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
//2. 实现原理
//2.1、设置两个变量 low、high,排序开始时:low=0,high=size-1。
//2.2、整个数组找基准正确位置,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面
//默认数组的第一个数为基准数据,赋值给key,即key=array[low]。
//因为默认数组的第一个数为基准,所以从后面开始向前搜索(high–),找到第一个小于key的array[high],就将 array[high] 赋给 array[low],即 array[low] = array[high]。(循环条件是 array[high] >= key;结束时 array[high] < key)
//此时从前面开始向后搜索(low++),找到第一个大于key的array[low],就将 array[low] 赋给 array[high],即 array[high] = array[low]。(循环条件是 array[low] <= key;结束时 array[low] > key)
//循环 2-3 步骤,直到 low=high,该位置就是基准位置。
//把基准数据赋给当前位置。
//2.3、第一趟找到的基准位置,作为下一趟的分界点。
//2.4、递归调用(recursive)分界点前和分界点后的子数组排序,重复2.2、2.3、2.4的步骤。
//2.5、最终就会得到排序好的数组。
/**
 * 快速排序
 *
 * 是否基于比较:是
 * 是否稳定排序:否
 * 是否原地操作:是
 * 时间复杂度为O(nlogn),因此大规模表现良好。
 * 适合排序数据类型:NSString,NSNumber,CGFloat,NSInteger,long
 **/
- (void)quickSortArray:(NSMutableArray *)array withLeftIndex:(NSInteger)leftIndex andRightIndex:(NSInteger)rightIndex {
    if (leftIndex >= rightIndex) {//如果数组长度为0或1时返回
        return ;
    }
    NSInteger i = leftIndex;
    NSInteger j = rightIndex;
    //记录比较基准数
    NSInteger key = [array[i] integerValue];
    
    while (i < j) {
        /**** 首先从右边j开始查找比基准数小的值 ***/
        while (i < j && [array[j] integerValue] >= key) {//如果比基准数大,继续查找
            j--;
        }
        //如果比基准数小,则将查找到的小值调换到i的位置
        array[i] = array[j];
        
        /**** 当在右边查找到一个比基准数小的值时,就从i开始往后找比基准数大的值 ***/
        while (i < j && [array[i] integerValue] <= key) {//如果比基准数小,继续查找
            i++;
        }
        //如果比基准数大,则将查找到的大值调换到j的位置
        array[j] = array[i];
    }
    
    //将基准数放到正确位置
    array[i] = @(key);
    
    /**** 递归排序 ***/
    //排序基准数左边的
    [self quickSortArray:array withLeftIndex:leftIndex andRightIndex:i - 1];
    //排序基准数右边的
    [self quickSortArray:array withLeftIndex:i + 1 andRightIndex:rightIndex];
    
    NSLog(@"快速排序 %@",array);                    
}

#pragma mark 希尔排序
/**
 * 希尔排序
 *
 * 是否基于比较:是
 * 是否稳定排序:是
 * 是否原地操作:是
 * 时间复杂度为O(n(1.3—2)),因此中等大小规模表现良好。
 * 适合排序数据类型:NSString,NSNumber,CGFloat,NSInteger,long
 **/
- (void)shellSortArray:(NSMutableArray *)array {//起始间隔值gap设置为总数的一半,直到gap==1结束
    int gap = (int)array.count / 2;
    while (gap >= 1) {
        for(int i = gap; i < [array count]; i++){
            NSInteger temp = [[array objectAtIndex:i] intValue];
            int j = i;
            while (j >= gap && temp < [[array objectAtIndex:(j - gap)] intValue]) {
                [array replaceObjectAtIndex:j withObject:[array objectAtIndex:j-gap]];
                j -= gap;
            }
            [array replaceObjectAtIndex:j withObject:[NSNumber numberWithInteger:temp]];
        }
        gap = gap / 2;
    }
    NSLog(@"希尔排序 %@",array);
}

//==========================堆排序============================
//堆排序
- (void)heapSortArray:(NSMutableArray *)array {
    NSInteger i,size;
    size = array.count;
    //找出最大的元素放到堆顶
    for (i = array.count/2-1; i >= 0; i--) {
        [self createBiggesHeap:array withSize:size beIndex:i];
    }
    
    while(size > 0){
        [array exchangeObjectAtIndex:size-1 withObjectAtIndex:0]; //将根(最大) 与数组最末交换
        size -- ;//树大小减小
        [self createBiggesHeap:array withSize:size beIndex:0];
    }
    NSLog(@"%@",array);
}

- (void)createBiggesHeap:(NSMutableArray *)array withSize:(NSInteger) size beIndex:(NSInteger)element {
    NSInteger lchild = element *2 + 1,rchild = lchild+1; //左右子树
    while (rchild < size) { //子树均在范围内
        if ([array[element] integerValue] >= [array[lchild] integerValue] && [array[element] integerValue] >= [array[rchild]integerValue]) return; //如果比左右子树都大,完成整理
        if ([array[lchild] integerValue] > [array[rchild] integerValue]) { //如果左边最大
            [array exchangeObjectAtIndex:element withObjectAtIndex:lchild]; //把左面的提到上面
            element = lchild; //循环时整理子树
        }else{//否则右面最大
            [array exchangeObjectAtIndex:element withObjectAtIndex:rchild];
            element = rchild;
        }
        
        lchild = element * 2 +1;
        rchild = lchild + 1; //重新计算子树位置
    }
    //只有左子树且子树大于自己
    if (lchild < size && [array[lchild] integerValue] > [array[element] integerValue]) {
        [array exchangeObjectAtIndex:lchild withObjectAtIndex:element];
    }
}
//==========================堆排序============================

//==========================归并排序============================
#pragma mark 归并排序
//时间复杂度为O(nlogn)
//(1)“分解”——将序列每次折半划分
//(2)“合并”——将划分后的序列段两两合并后排序
/**
 * 归并排序
 *
 * 是否基于比较:是
 * 是否稳定排序:是
 * 是否原地操作:否
 * 时间复杂度为O(nlogn),因此大规模表现良好。
 * 适合排序数据类型:NSString,NSNumber,CGFloat,NSInteger,long
 **/
- (void)megerSortAscendingOrderSort:(NSMutableArray *)ascendingArray {
    // 排序数组
    NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:1];
    // 第一趟排序是的子数组个数为ascendingArr.count
    for (NSNumber *num in ascendingArray) {
        NSMutableArray *subArray = [NSMutableArray array];
        [subArray addObject:num];
        [tempArray addObject:subArray];
    }
    /**
     分解操作 每一次归并操作
     当数组个数为偶数时tempArray.count/2; 当数组个数为奇数时tempArray.count/2+1; 当tempArray.count == 1时,归并排序完成
     */
    while (tempArray.count != 1) {
        NSInteger i = 0;
        // 当数组个数为偶数时 进行合并操作, 当数组个数为奇数时,最后一位轮空
        while (i < tempArray.count - 1) {
            // 将i 与i+1 进行合并操作 将合并结果放入i位置上 将i+1位置上的元素删除
            tempArray[i] = [self mergeArrayFirstList:tempArray[i] secondList:tempArray[i + 1]];
            [tempArray removeObjectAtIndex:i + 1];
            // i++ 继续下一循环的合并操作
            i++;
        }
    }
    NSLog(@"归并升序排序结果:%@", tempArray[0]);
}

// 合并
- (NSArray *)mergeArrayFirstList:(NSArray *)array1 secondList:(NSArray *)array2 {
    // 合并序列数组
    NSMutableArray *resultArray = [NSMutableArray array];
    // firstIndex是第一段序列的下标 secondIndex是第二段序列的下标
    NSInteger firstIndex = 0, secondIndex = 0;
    // 扫描第一段和第二段序列,直到有一个扫描结束
    while (firstIndex < array1.count && secondIndex < array2.count) {
        // 判断第一段和第二段取出的数哪个更小,将其存入合并序列,并继续向下扫描
        if ([array1[firstIndex] floatValue] < [array2[secondIndex] floatValue]) {
            [resultArray addObject:array1[firstIndex]];
            firstIndex++;
        } else {
            [resultArray addObject:array2[secondIndex]];
            secondIndex++;
        }
    }
    // 若第一段序列还没扫描完,将其全部复制到合并序列
    while (firstIndex < array1.count) {
        [resultArray addObject:array1[firstIndex]];
        firstIndex++;
    }
    // 若第二段序列还没扫描完,将其全部复制到合并序列
    while (secondIndex < array2.count) {
        [resultArray addObject:array2[secondIndex]];
        secondIndex++;
    }
    // 返回合并序列数组
    return resultArray.copy;
}
//==========================归并排序============================


//==========================基数排序============================
#pragma mark --- 基数排序
/**
 * 基数排序
 *
 * 是否基于比较:否(线性排序)
 * 是否稳定排序:是
 * 是否原地操作:否
 * 时间复杂度为更低的O(n),但是对要排序的数据要求很苛刻,基数排序要求数据可以划分成高低位,位之间有递进关系。比较两个数,我们只需要比较高位,高位相同的再比较低位。而且每一-位的数据范围不能太大。
 * 适合排序数据类型:NSString,NSNumber,NSInteger,long
 **/
- (void)radixSortArray:(NSMutableArray *)array {
    NSMutableArray *bucket = [self createBucket];
    double maxNumber = [self listMaxItem:array];
    NSInteger maxLength = [self numberLength:maxNumber];
    
    for (NSInteger digit = 1; digit <= maxLength; digit++)  {
        //入桶
        for (NSNumber *number in array) {
            NSInteger baseNumber = [self fetchBaseNumber:number.doubleValue digit:digit];
            NSMutableArray *subArray = bucket[baseNumber];
            [subArray addObject:number];
        }
        
        //出桶
        NSInteger index = 0;
        
        for (NSInteger i = 0; i < bucket.count; i++) {
            NSMutableArray *subArray = bucket[i];
            while (subArray.count > 0) {
                NSNumber *item = subArray[0];
                [array replaceObjectAtIndex:index withObject:item];
                [subArray removeObjectAtIndex:0];
                index++;
            }
        }
    }
    NSLog(@"基数排序 %@",array);
}

//创建10个空桶
- (NSMutableArray *)createBucket {
    NSMutableArray *bucketArray = [NSMutableArray array];
    for (NSInteger i = 0; i < 10; i++) {
        [bucketArray addObject:[NSMutableArray array]];
    }
    return bucketArray;
}

//计算无序序列中最大的数值
- (double)listMaxItem:(NSArray *)array {
    double maxNumber = [array[0] doubleValue];
    for (NSNumber *number in array) {
        if (maxNumber < number.doubleValue) {
            maxNumber = number.doubleValue;
        }
    }
    return maxNumber;
}

//获取数字的长度
- (NSInteger)numberLength:(double)number {
    NSString *numberStr = [NSString stringWithFormat:@"%f",number];
    return numberStr.length;
}

//获取数值中特定位数的值
- (NSInteger)fetchBaseNumber:(double)number digit:(NSInteger)digit {
    if (digit > 0 && digit <= [self numberLength:number]) {
        NSMutableArray *numbersArray = [NSMutableArray array];
        NSString *numberStr = [NSString stringWithFormat:@"%f",number];
        for (NSInteger i = 0; i < numberStr.length; i++) {
            NSString *subStr = [numberStr substringWithRange:NSMakeRange(i, 1)];
            [numbersArray addObject:[NSNumber numberWithInteger:subStr.doubleValue]];
        }
        return [numbersArray[numbersArray.count - digit] integerValue];
    }
    return 0;
}
//==========================基数排序============================






/**
 * 二分查找(循环)
 **/
- (NSInteger)binarySearch:(NSArray *)source target:(NSInteger)target {
    if (source.count == 0) {
        return -1;
    }
    NSInteger start = 0;
    NSInteger end = source.count - 1;
    NSInteger mid = 0;
    
    while (start + 1 < end) {
        mid = start + (end - start) / 2;
        if ([source[mid] integerValue] == target) { // 相邻就退出
            return mid;
        } else if ([source[mid] integerValue] < target) {
            start = mid;
        } else {
            end = mid;
        }
    }
    
    if ([source[start] integerValue] == target) {
        return start;
    }
    if ([source[end] integerValue] == target) {
        return end;
    }
    
    return -1;
}

@end
上一篇 下一篇

猜你喜欢

热点阅读