“这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战”
关注我,以下内容持续更新
排序的分类
- 插入排序: 直接插入排序 希尔排序
- 交换排序: 冒泡排序 快速排序
- 选择排序: 简单选择排序 堆排序
- 归并排序
本篇主要讲解直接插入排序
直接插入排序
插入排序的主要操作是插入. 核心:在插入第i(i>1)个元素时,前面的 i-1 个元素已经排好.
基本思想:把n个待排序的元素看成为一个有序表和一个无序表,初始状态将第一个元素看成是初始有序表,无序表中包含有后边的n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表。
代码实现:双层循环,首先假设array[0]已经排好序,第一层循环从array[1]开始,每次内层循环都是array[i]和有序表中的元素依次比较,找到合适的位置就插入,也就是前边的元素如果比自己大,那么前边的元素往后移,否则就找到正确的位置,停止本轮内层循环,插入到此位置。每轮循环走完后都可以保证i左边的元素是有序的。
插入排序有交换法和移位法,用移位法效率更好,因为减少了交换次数。
//2.1 插入排序--移位法 (while 循环 实现)
-(void)insertSort:(NSMutableArray*)arr{
for (int i = 1; i<arr.count; i++) {
int tmp = [arr[i] intValue];//当前值是要比较的值
int j = i;//j代表要插入的位置,tmp要和 j-1 比较,如果tmp大,则插入到j-1后面的位置,就是 j
while (j>0 && tmp < [arr[j-1] intValue]) {
arr[j] = arr[j-1];//前边的元素往后移动一位
j--;//循环
}
arr[j] = @(tmp);//把要比较的元素插入在正确的位置
}
}
//2.1 插入排序---移位法 (for循环实现)
-(void)insertSort:(NSMutableArray*)arr{
for (int i = 1; i<arr.count; i++) {
//暂存arr[i]的值,也就是要插入的值,使其不至于因为元素的后移而丢失元素的内容
int tmp = [arr[i] intValue];
int j = i;
for (;j>0; j--) {//j代表要插入的位置,tmp要和j的前一个位置比较,如果符合顺序就停止循环直接插入到j
if (tmp < [arr[j-1] intValue]) {//如果tmp比前边的小,继续循环,并把arr[j-1]后移
arr[j] = arr[j-1];//前边的元素往后移动一位
}else{//如果遇到正确的位置,并退出循环;因为for循环的条件是>0,所以退出循环后,再插入到正确的位置
break;
}
}
arr[j] = @(tmp);//直接插入到j
}
}
//2.2 插入排序 -- 交换法 (性能差,每次比较都交换)
-(void)insertSort:(NSMutableArray*)arr{
for (int i = 1; i<arr.count; i++) {
for (int j = i; j>0; j--) {
if ([arr[j] intValue] < [arr[j-1] intValue]) {
NSNumber*tmp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = tmp;
}
}
}
}
性能分析
直接插入排序性能分析:
-
最好情况下(正序):
比较次数 n-1;移动次数 2(n-1),时间复杂度为 o(n)
-
最坏情况下(逆序):
比较次数 n-1;移动次数 2(n-1),时间复杂度为 o(n²)
-
平均情况下(随机序列):
时间复杂度为 o(n²)
另外,还需要一个记录的辅助空间来暂存要插入的元素,防止元素的后移而丢失元素的内容
直接插入排序的优化
直接插入排序算法简单,容易实现,适用于基本有序的序列或个数较少的序列,当待排序的元素较多时,大量的比较和移动会导致性能降低.
优化方向1: 在插入第i(i>1)个元素时,前面的 i-1 个元素已经排好,在查找插入位置时,可以用二分查找来代替顺序查找,从而减少比较次数.
优化方向2:当较小的数在序列的偏后面的位置时,后移的次数明显增多,对效率有影响。针对这一点,希尔排序做出了优化,通过设置一个增量gap,使得序列基本有序.
其他排序算法
关注我
如果觉得我写的不错,请点个赞 关注我 您的支持是我更文最大的动力!