C语言—零基础学习插入排序和希尔排序——插入排序

插入排序和希尔排序是我们虽然是初期接触的比较简单的排序,但是在代码实现时,也有不好理解的点,本文会从零开始介绍插入排序和希尔排序的思路和代码实现的过程并把所有的坑列举出来相信看完本文你将会对这两个排序有很清楚的理解。本文所有排序按照从小到大的顺序排列。

插入排序思路:

插入排序可以类比我们理扑克牌的过程,我们从无序牌堆摸牌插入手上已经理好顺序的手牌

给定一个数组arr【5,3,4,6,7】,利用插入排序进行排序,第一个元素可以认为已经有序,直接从第二个元素开始往前插入,现在可以把这个数组看做两个数组:有序数组【5】和无序数组【3,4,6,7】,

将无序数组第一个元素3插入前面的有序数组,将3与5比较,3比5小,应该在5的前面。直接将3和5的顺序交换,此时原数组就变为了【3,5,4,6,7】,可看成【3,5】和【4,6,7】,此时再把4插入前面的有序数组,先和5比较,4比5小,应该在5前面,所以4和5换位置,

然后4再和3比较,4比3大,所以4此时的位置是正确的

从上面的比较我们可以总结出规律

将无序数组的第一个数arr【i】(也叫作被插入的数,i为它的下标),和有序数组的最后一个数arr【j】(j为该数的下标,j=i-1)比较,如果arr【i】<arr【j】,则arr【i】与arr【j】交换位置,此时arr【j】就是被插入的数,然后arr【j】继续和有序数组的前一个数arr【j-1】比较,直到

(1)所选的有序数组的数小于被插入的数

或者

(2)比较完所有的有序数,此时j=0,插入数已经是有序数组的头元素

然后再插入无序数组的下一个数,直到将数组所有元素插入完毕

怎么样,是不是很简单呢?但是这只是插入排序的大致的思路,真正的插入排序还需要优化一些细节,有优化意识的小伙伴已经发现了,我们上述的交换顺序有点太啰嗦了,如果一个本该被排到0位置的插入数,要插入一个长度为10000的有序数组,那它将被重复的交换到不是正确位置次数有9999次,这样显然浪费了资源

我们可以把要插入的数用一个临时变量tem存起来,直接用tem和前面的有序数组比较,如果arr【j】>tem,直接把arr【j】赋值给arr【j+1】,并且不把tem赋值给arr【j】,然后j--,继续比较,直到

(1)tem>arr【j】,把tem的值赋值个arr【j+1】;

或者

(2)j=-1,此时tem已经与所有有序数组的元素比较完,有序数组元素下标都后退了一位,此时也把tem的值赋给arr【j+1】;

这样我们就一次就把被插入数赋值到了正确的位置,这才是真正的插入排序

插入排序代码:

void insertSort(int arr[])
{
    for(int i=1;i<sizeof(arr)/4;i++)
    {
        int j=i-1;
        int tem=arr[i];
        for(;j>=0;j--)
        {
            if(arr[j]>tem)
            {
                arr[j+1]=arr[j];
            }
            else
            {
                break;
            }
        }
            arr[j+1]=tem;
    }
}

时刻牢记,i下标为被插入数的下标,刚开始时,第一个数是默认有序的,所以i的初始值为1

j下标为有序数组最后一个元素的下标,等于i-1;

这个代码有一个很多同学会踩的坑,就是在把arr【j+1】=tem这一步放在else语句的break前面,

这样写在一种特殊情况下会出现bug,就是当内层的for-j循环中这个arr【j】每次都大于tem的时候(也就是tem为有序数组的最小数),每次循环都只执行if条件下的的代码

 

tem没有机会被赋值给arr【j+1】,因为此时j=-1,已经退出这个循环了

 

以上就是插入循环的思路代码,你学会了吗?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值