20*:排序算法3:插入排序(从未排序区间依次取出元素插入到排序区间的适当位置。稳定)

问题

-(void)insertSequence:(NSMutableArray *)arr
{
    for (int i = 1; i<arr.count; i++) {
        int a=[arr[i] intValue];
        int k = i;
        while (k>0&&[arr[k] intValue]>a) {
            arr[k + 1] = arr[k];
            k--;
        }
        arr[k+1] = [NSString stringWithFormat:@"%d",a];
        NSLog(@"%@",arr);
    }
}

目录

 

预备

 

正文

插入排序

1:算法描述

插入排序类似于大多数人安排扑克牌的方式。

插扑克牌之插入排序

  • 从你手中的一张牌开始,
  • 选择下一张卡并将其插入到正确的排序顺序中,
  • 对所有的卡重复上一步。

2:算法思想

插入排序和选择排序一样,都分已排序区和位排序区。

将第一个元素标记为已排序

遍历每个没有排序过的元素

 “提取” 元素 X

 i = 最后排序过元素的指数 到 0 的遍历

  如果现在排序过的元素 > 提取的元素

     将排序过的元素向右移一格

  否则:插入提取的元素

3:动图演示

 

  •  红色代表选中的需要排序的。
  • 黄色的条代表已经排好序的元素;

  • 绿色的代表此算法正在操作,进行比较交换的元素

  • 蓝色代表还没有排序的

4:代码实现

public class InsertSort {
    public static int[] insertSort(int[] arr) {
        if(arr == null || arr.length < 2)
            return arr;

        int n = arr.length;
        // 下标为0的数默认是有序的,从下标为1的数开始遍历,将其放入他该去的地方
        for (int i = 1; i < n; i++) {
            // 申请一个变量记录要插入的数据,也就是动图中红色的元素
            int tmp = arr[i];

            // 从已经排序的序列最右边的开始比较,找到比其小的数,即动图中绿色的元素序号
            int j = i;
            // 红色元素下标大于0,要插入元素与遍历到的元素满足大小关系,遍历到的元素往后挪位腾位置        
        // 继续遍历,直到不满足大小关系停止,这个地方就是它的位置 // 即红色元素小于绿色元素时,绿色元素挪位 while (j > 0 && tmp < arr[j - 1]) { // 绿色元素往后挪一位 arr[j] = arr[j - 1]; j--; } // 存在比其小的数,插入 if (j != i) { arr[j] = tmp; } } return arr; } }
  • 稳定性分析

    稳定。在插入排序中,对于值相同的元素,我们可以选择将后面出现的元素,插入到前面出现元素的后面,这样就可以保持原有的前后顺序不变,所以插入排序是稳定的排序算法。

  • 时间复杂度分析

    如果要排序的数据已经是有序的,我们并不需要搬移任何数据。如果我们从尾到头在有序数据组里面查找插入位置,每次只需要比较一个数据就能确定插入的位置。所以这种情况下,最好是时间复杂度为O(n)。注意,这里是从尾到头遍历已经有序的数据。

    如果数组是倒序的,每次插入都相当于在数组的第一个位置插入新的数据,所以需要移动大量的数据,所以最坏情况时间复杂度为O(n2)。

 

OC语言

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

时间空间复杂度与冒泡排序一致

-(void)insertSequence:(NSMutableArray *)arr
{
    for (int i = 1; i<arr.count; i++) {
        int a=[arr[i] intValue];
        int k = i-1;
        while (k>=0&&[arr[k] intValue]>a) {
            arr[k + 1] = arr[k];
            k-=1;
        }
        arr[k+1] = [NSString stringWithFormat:@"%d",a];
        NSLog(@"%@",arr);
    }
}

// 或者
NSMutableArray *InsetSort(NSMutableArray *mArray, NSInteger start) {
    
    if (start == mArray.count) {
        return mArray;
    }
    for (NSInteger i = start; i > 0; i --) {
        if ([mArray[i] intValue] < [mArray[i-1] intValue]) {
            int temp = [mArray[i] intValue];
            int k =  (int)(i - 1);
            
            while (k >= 0 && [mArray[k] intValue] > temp) {
                mArray[k + 1] = mArray[k];
                k -= 1;
            }
            mArray[k+1] = [NSString stringWithFormat:@"%d",temp];
        }
    }
    InsetSort(mArray, start + 1);
    return mArray;
}

插入排序优势:对于有序数组或部分有序数组,此排序方法是十分高效的,很适合小规模的数组,很多高级的排序算法都会利用到插入排序。

插入排序劣势:若果最少的元素都在最后部分的位置,那么该排序方法就会变得非常费劲了,最后的元素都要比较该元素位置减一次。

注意

 

引用

1:极客算法训练笔记(五),十大经典排序之冒泡,选择,插入排序

2:OC-排序算法总结(冒泡、快速、插入、选择、希尔、堆)

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

导航