25*:排序算法:总结 (1、冒泡排序:2:选择排序:3、插入排序:4、希尔排序:5、堆排序:6、归并排序:7、快速排序:)

问题

 

目录

1、冒泡排序:未排序区间两两交换找到最大值,排在最后,形成有序区间。稳定

2:选择排序:从未排序区间找最小元素,和排序区间的最后一个元素交换位置。

3、插入排序:从未排序区间依次取出元素插入到排序区间的适当位置。稳定

4、希尔排序:缩小增量排序

5、堆排序:完全二叉树大堆顶,交互堆顶和最后元素,找到最大元素。循环在未排序区间找到最大元素,依次排序。

6、归并排序:两两分而治之。稳定

7、快速排序:分区值,分而治之

预备

 

正文

1、冒泡排序:未排序区间交换找到最大值,排在最后,形成有序区间。稳定

原理:

1:这种算法会重复的比较数组中相邻的两个元素,如果一个元素比另一个元素大(小),那么就交换这两个元素的位置。重复这一比较直至最后一个元素。每一趟比较都能找出未排序元素中最大或者最小的那个数字。这就如同水泡从水底逐个飘到水面一样。冒泡排序是一种时间复杂度较高,效率较低的排序方法。

2:这一比较会重复n-1趟,每一趟比较n-j次,j是已经排序好的元素个数。

每一趟会找到最大(或者最小)的数据,排成有序区间,之后在没有排序区间的n-j中找最大或者最小数据再排列。

时间复杂度:O(n^2),优化后可能达到O(n),但会增加空间复杂度

-(void)bubbleSequence:(NSMutableArray *)arr
{
    //普通排序-交换次数较多
    for (int i = 0; i < arr.count; ++i) {
        for (int j = 0; j < arr.count-1-i; ++j) {
            if ([arr[j+1] intValue] < [arr[j] intValue]) {     
[arr exchangeObjectAtIndex:j withObjectAtIndex:j+1]; } } } //优化后算法-从最后一个开始排序 for (int i = 0; i <arr.count; ++i) { bool flag=false; //遍历数组的每一个`索引`(不包括最后一个,因为比较的是j+1) for (int j = (int)arr.count-1; j >i; --j) { //根据索引的`相邻两位`进行`比较` if ([arr[j-1] intValue] > [arr[j] intValue]) { flag = true; [arr exchangeObjectAtIndex:j withObjectAtIndex:j-1]; } } if (!flag) { break;//没发生交换直接退出,说明是有序数组 } } }

2:选择排序:从未排序区间找最小元素,和排序区间的最后一个元素交换位置。

原理:

选择排序分已排序区间和未排序区间。从第一个元素开始,依次查找对比,找到最小的元素与第一个元素交换,再从第二个元素(没有排序区间的第一个元素)开始找后面元素的最小值与第二个元素交换,以此类推,直到整个数组有序。 

时间复杂度:O(n^2)

- (void)selectionAscendingOrderSortWithArray:(NSMutableArray *)ascendingArr
{
    int index = 0;//记录找到的关键字下标
    for (int i = 0; i < arr.count - 1; i++) {
      index = i;
      for (int j = i + 1; j < arr.count; j++) {
          if ([arr[index] integerValue] < [arr[j]integerValue]) {
            //如果有比当前index值大的值,则记录次下标
            index = j;//记录最大值(最小值)的下标
          }
      }
      if (i != index) {  //若index不等于i,说明找到最大值,交换
          [arr exchangeObjectAtIndex:i withObjectAtIndex:index];
      }
    NSLog(@"%@",arr);
}

3、插入排序:从未排序区间依次取出元素插入到排序区间的适当位置。稳定

原理:
插入排序分已排序区和位排序区。
由数组的第2个位置开始比较,若果前方位置的元素比较大,则交换位置,若自己元素较大,而继续下一个元素,如此排列,那么被操作的那个元素前方位置的所有元素皆为有序。最坏情况下需要~ N^2/2 次比较和~ N^2/2 次交换,最好情况下需要 N-1次比较和 0 次交换

时间复杂度:O(n^2)

#pragma mark - 插入升序排序
- (void)insertionAscendingOrderSort:(NSMutableArray *)ascendingArr
{
    for (NSInteger i = 1; i < ascendingArr.count; i ++) {
        NSInteger temp = [ascendingArr[i] integerValue];
        for (NSInteger j = i - 1; j >= 0 && temp < [ascendingArr[j] integerValue]; j --) {
            ascendingArr[j + 1] = ascendingArr[j];
            ascendingArr[j] = [NSNumber numberWithInteger:temp];
        }
    }
    NSLog(@"插入升序排序结果:%@",ascendingArr);
}

4、希尔排序:缩小增量排序

原理:

1:使用分组的方式,分组策略使用一个递减序列,每组依然使用插入排序算法进行组内排序。即局部有序

2:一直分组下去,直到分组为1,组内就是全部元素了,分组越少,组内成员就越多,局部有序元素就越多,即全部有序,全排序。

时间复杂度:O(n logn)

//起始间隔值gap设置为总数的一半,直到gap==1结束
-(void)shellSort:(NSMutableArray *)list{
    int gap = (int)list.count / 2;
    while (gap >= 1) {
        for(int i = gap ; i < [list count]; i++){
            NSInteger temp = [[list objectAtIndex:i] intValue];
            int j = i;
            while (j >= gap && temp < [[list objectAtIndex:(j - gap)] intValue]) {
                [list replaceObjectAtIndex:j withObject:[list objectAtIndex:j-gap]];
                j -= gap;
            }
            [list replaceObjectAtIndex:j withObject:[NSNumber numberWithInteger:temp]];
        }
        gap = gap / 2;
    }
}

5、堆排序:完全二叉树大堆顶,交互堆顶和最后元素,找到最大元素。循环在未排序区间找到最大元素,依次排序。

原理

1: 从下往上,从右往左的顺序查找每个非叶子结点,对比子结点,与最大结点交换位置,交换的新位置再与其子结点比较、移动,遍历后最终找到最大值,形成一个大顶堆(小顶堆也行)。

2:把堆顶和最后的元素交换位置,排除最后的位置,重复1步骤,找到遍历后的最大值,放到倒数第二的位置,依次直到结束。

时间复杂度:O(n logn)

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

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

6、归并排序:两两分而治之。稳定

原理

1:分治,分而治之,将原数组一直拆分成左右两个小数组,直至小数组元素个数为1,

2:然后每两个小数组进行有序归并,直至归并成一个完整的数组,从而达到整个数组有序的目的。由于每两个小的数组都是有序的,所以在每次合并的时候是很快的。合并的时候用插入排序形成有序区间。

时间复杂度:O(n logn)

- (void)megerSortAscendingOrderSort:(NSMutableArray *)ascendingArr
{
    //tempArray数组里存放ascendingArr个数组,每个数组包含一个元素
    NSMutableArray *tempArray = [NSMutableArray arrayWithCapacity:1];
    for (NSNumber *num in ascendingArr) {
        NSMutableArray *subArray = [NSMutableArray array];
        [subArray addObject:num];
        [tempArray addObject:subArray];
    }
    //开始合并为一个数组
    while (tempArray.count != 1) {
        NSInteger i = 0;
        while (i < tempArray.count - 1) {
            tempArray[i] = [self mergeArrayFirstList:tempArray[i] secondList:tempArray[i + 1]];
            [tempArray removeObjectAtIndex:i + 1];
            i++;
        }
    }
    NSLog(@"归并升序排序结果:%@", tempArray[0]);
}

- (NSArray *)mergeArrayFirstList:(NSArray *)array1 secondList:(NSArray *)array2 {
    NSMutableArray *resultArray = [NSMutableArray array];
    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;
}

7、快速排序:分区值,分而治之

原理:

1:每次选一个pivot(分区值),其他数依次和 pivot 比较,大的放右边小的放左边,

2:然后再对左边和右边的两组数,分别选出pivot,重复比较,大的放左边,小的放右边;重复步骤,直到最后都变成单个元素,整个数组就成了有序的序列。

时间复杂度:O(n logn)

-(void)quickSequence:(NSMutableArray *)arr andleft:(int)left andright:(int)right
{
    if (left >= right) {//如果数组长度为0或1时返回
        return ;
    }
    int key = [arr[left] intValue];
    int i = left;
    int j = right;
    
    while (i<j){
        while (i<j&&[arr[j] intValue]>=key) {
            j--;
        }
        arr[i] = arr[j];
        
        while (i<j&&[arr[i] intValue]<=key) {
            i++;
        }
        arr[j] = arr[i];
    }
    arr[i] = [NSString stringWithFormat:@"%d",key];
    [self quickSequence:arr andleft:left andright:i-1];
    [self quickSequence:arr andleft:i+1 andright:right];
} 

注意

 

引用

posted on 2020-12-16 20:18  风zk  阅读(234)  评论(0编辑  收藏  举报

导航