算法或者代码iOS高效开发者

算法(一)

2017-10-17  本文已影响9人  小熊翻译App

以下算法参考 <<算法>> 第4版[美] Robert Sedgewick

1. 欧几里德算法
- (void)viewDidLoad {
    [super viewDidLoad];
    [self calculateGreatestCommonDivisorP:30 q:6]; //欧几里德算法:求两个数的最大公约数
}
#pragma mark - 欧几里德算法
/**
 计算两个非负整数 p 和 q 的最大公约数:若 q 是 0,则最大公约数为 p。否则,将 p 除以 q得到余数r,p和q的最大公约数即为q和 r 的最大公约数。
 greatest common divisor: 最大公因子
 */
- (int)calculateGreatestCommonDivisorP:(int)p q:(int)q {
    NSLog(@"p 和 q 的最大公约数============ %d", gcd(p, q));
    return gcd(p,q);
}

int gcd (int p, int q) {
    if (q == 0) {
        return p;
    }
    int r = p % q;
    return gcd(q, r);
}

2. 找出数组中组大的元素
- (void)viewDidLoad {
    [super viewDidLoad];
    NSArray *array = @[@2.6, @3, @9.6, @8, @5, @6];
    [self getMaxNumInArray:array];    //找出数组中组大的元素
}
- (NSNumber *)getMaxNumInArray:(NSArray *)array
 {
    double max = [array[0] doubleValue];
    for (int i = 1; i < array.count; i ++) {
        if ([array[i] doubleValue] > max) {
            max = [array[i] doubleValue];
        }
    }
    NSLog(@"MaxNumInArray===========%@", @(max));
    return @(max);
}
注:这里不能直接用 NSNumber, 直接用 NSNumber 浮点数会出错.
3. 计算数组元素的平均值
- (void)viewDidLoad {
    [super viewDidLoad];
    NSArray *array = @[@2.6, @3, @9.6, @8, @5, @6];
    [self calculateAverageInArray:array];    // 计算数组元素的平均值
}
- (NSNumber *)calculateAverageInArray:(NSArray *)array {
    NSInteger length = array.count;
    double sum = 0.0;
    double average = 0.0;
    for (NSInteger i = 0; i < length; i ++) {
        sum += [array[i] doubleValue];
        average = sum / length;
    }
    NSLog(@"calculateAverage===========%@", @(average));
    return @(average);
}
4. 复制数组
注:示例数组中是NSNumber类型元素,其它类型需要另写方法
- (void)viewDidLoad {
    [super viewDidLoad];
    [self copyArray:array];     // 复制数组:示例数组中是数字
}
- (NSArray *)copyArray:(NSArray *)array {
    NSInteger length = array.count;
    NSMutableArray * copyArrayM = [NSMutableArray array];
    for (NSInteger i = 0; i < length; i ++) {
        copyArrayM[i] = array[i];
    }
    NSArray *copyArray = copyArrayM;
    return copyArray;
}
5. 颠倒数组元素的顺序
- (void)viewDidLoad {
    [super viewDidLoad];
    [self reverseArray:array];  // 颠倒数组元素的顺序
}
- (NSArray *)reverseArray:(NSArray *)array {
    NSInteger N = array.count;
    NSMutableArray *arrayM = [NSMutableArray array];
    for (NSInteger i = 0; i < N; i ++) {
        [arrayM addObject:array[i]];
    }
    for (NSInteger i = 0; i < N/2; i++) {
        NSNumber *temp = arrayM[i];
        arrayM[i] = arrayM[N-1-i];
        arrayM[N-i-1] = temp;
    }
    array = arrayM;
    return array;
}

-----------典型静态方法的实现-------------

6. 计算一个数的绝对值:浮点数和整数
- (void)viewDidLoad {
    [super viewDidLoad];
    NSNumber *numAbs = [self calculateNumAbs:-234];
    NSLog(@"calculateDoubleAbs========%@", numAbs);
}
- (NSNumber *)calculateNumAbs:(double)x {
    if (x<0.0) {
        return @(-x);
    }
    else {
        return @(x);
    }
}
7. 判定一个数是否是素数:prime number
- (void)viewDidLoad {
    [super viewDidLoad];
    BOOL isPrime = [self isPrime:17];   // 判定一个数是否是素数
    NSLog(@"isPrime===========%d", isPrime);
}
- (BOOL)isPrime:(NSInteger)N {
    if (N < 2) {
        return false;
    }
    for (NSInteger i = 2; i*i <= N; i++) {
        if (N % i == 0) {
            return false;
        }
    }
    return true;
}
8. 计算平方根(牛顿迭代法)
- (void)viewDidLoad {
    [super viewDidLoad];
    double numSqrt = [self calculateSqrt:-1];
    NSLog(@"numSqrt=========%f", numSqrt);
}
- (double)calculateSqrt:(double)c {
    if (c < 0) {
        return NAN;
    }
    double err = 1e-15;
    double t = c;
    while (fabs(t - c/t) > err * t) {
        t = (c/t + t) / 2.0;
    }
    return t;
}
9. 计算直角三角形的斜边
- (void)viewDidLoad {
    [super viewDidLoad];
    double hypotenuse = [self calculateHypotenuse:5 :12];
    NSLog(@"hypotenuse=========%f", hypotenuse);
}
- (double)calculateHypotenuse:(double)a :(double)b {
    return sqrt(a*a + b*b);
}
10. 计算调和级数
- (void)viewDidLoad {
    [super viewDidLoad];
    double HarmonicSeries = [self calculateHarmonicSeries:5];
    NSLog(@"HarmonicSeries=========%f", HarmonicSeries);
}
- (double)calculateHarmonicSeries:(NSInteger)N {
    double sum = 0.0;
    for (int i = 1; i <= N; i++) {
        sum += 1.0 / i;
    }
    return sum;
}
11. 二分查找的递归实现
注: 二分查找的递归实现: 数组内数字大小是有序的(从大到小)
- (void)viewDidLoad {
    [super viewDidLoad];
    NSArray *intArray = @[@2, @3, @4, @10, @19, @20];
    NSInteger rankNum = [self rank:20 :intArray];
    NSLog(@"rankNum=========%ld", (long)rankNum);
}
- (NSInteger)rank:(NSInteger)key :(NSArray<NSNumber *> *)array {
    return [self rank:key :array :0 :array.count - 1];
}
- (NSInteger)rank:(NSInteger)key :(NSArray *)array :(NSInteger)low :(NSInteger)high {
    //如果key存在于a[]中,它的索引不会小于low且不会大于high
    if (low > high) {
        return -1;
    }
    NSInteger mid = low + (high - low) / 2;
    if (key < [array[mid] integerValue]) {  //若小于array[mid],则往前查找
        return [self rank:key :array :low :mid-1];
    }
    else if (key > [array[mid] integerValue]) { //若大于array[mid],则往后查找
        return [self rank:key :array :mid+1 :high];
    }
    else {
        return mid;
    }
}

关于递归:编写递归代码时最重要的有以下三点
1. 递归总有一个最简单的情况——方法的第一条语句总是一个包含 return 的条件语句。
2. 递归调用总是去尝试解决一个规模更小的子问题,这样递归才能收敛到最简单的情况。上面的代码中,第四个参数和第三个参数的差值一直在缩小。
3. 递归调用的父问题和尝试解决的子问题之间不应该有交集。上面的代码中,两个子问题各自操作的数组部分是不同的。

-----------随机数---------

12. 随机返回 [a,b) 之间的一个 double 值
- (void)viewDidLoad {
    [super viewDidLoad];
    double doubleRandom = [self uniform:1 :3];
    NSLog(@"doubleRandom=========%f", doubleRandom);
}
- (double)uniform:(double)a :(double)b {
    #define ARC4RANDOM_MAX      1000000
    return a + ((double)(arc4random()%ARC4RANDOM_MAX)/ARC4RANDOM_MAX) * (b-a);
}
13. 随机返回 [0,N-1] 之间的整数,值域:[0,N-1]
- (void)viewDidLoad {
    [super viewDidLoad];
    NSInteger intRandomZeroToHigh = [self arc4randomHigh:5];
    NSLog(@"intRandomZeroToHigh=========%ld", (long)intRandomZeroToHigh);
}
- (NSInteger)arc4randomHigh:(NSInteger)high {
    return arc4random() % high;
}
14. 随机返回 [low,high-1] 之间的整数,值域:[low,high]
- (void)viewDidLoad {
    [super viewDidLoad];
    NSInteger intRandomLowToHigh = [self arc4randomLow:3 high:5];
    NSLog(@"intRandomLowToHigh=========%ld", (long)intRandomLowToHigh);
}
- (NSInteger)arc4randomLow:(NSInteger)low high:(NSInteger)high {
    return low + arc4random() % (high-low);
}
15. 根据离散概率随机返回的 int 值(出现 i 的概率为 a[i])
- (void)viewDidLoad {
    [super viewDidLoad];
    NSArray *discreteArray = @[@0.2,@0.09,@0.3,@0.11,@0.3]; // a[]中各元素之和必须等于1
    NSInteger discrete = [self discrete:discreteArray];
    NSLog(@"discrete=======%zd", discrete);
}
- (NSInteger)discrete:(NSArray *)array {
    // a[]中各元素之和必须等于1
    #define ARC4RANDOM_MAX      1000000
    double r = (double)(arc4random()%ARC4RANDOM_MAX)/ARC4RANDOM_MAX;    // [0,1)随机数
    double sum = 0.0;
    for (NSInteger i = 0; i < array.count; i++) {
        sum = sum + [array[i] doubleValue];
        if (sum >= r) {
            return i;
        }
    }
    return -1;
}
16. 随机将 double 数组中的元素排序
- (void)viewDidLoad {
    [super viewDidLoad];
    NSArray *beforeShuffleArray = @[@2,@10.09,@2.3,@0.11,@6.3];
    NSArray *afterShuffleArray = [self shuffle:beforeShuffleArray];
    NSLog(@"afterShuffleArray = %@", afterShuffleArray);
}
/// 随机将 double 数组中的元素排序
- (NSMutableArray *)shuffle:(NSArray *)array {
    NSMutableArray *arrayM = [NSMutableArray array];
    for (NSNumber *num in array) {
        [arrayM addObject:num];
    }
    NSInteger N = arrayM.count;
    for (NSInteger i = 0; i < N; i++) {
        // 将a[i]和a[i..N-1]中任意一个元素交换
        NSInteger r = i + arc4random() % (N-i);
        double temp = [arrayM[i] doubleValue];
        arrayM[i] = arrayM[r];
        arrayM[r] = @(temp);
    }
    return arrayM;
}
上一篇 下一篇

猜你喜欢

热点阅读