插入排序-直接插入排序

 一、基本思想

        直接插入排序是一种较为简单的排序算法,形象地比喻,就很像你打扑克牌时,不停的向你已经排好的牌中插入你的牌,直到你“牌”插完,一副牌也就牌好了(下图只是看看,打的时候反正我从不这样拿牌!)

         但好歹是这一个众所皆知的排序算法,肯定有较为正式一点的说法,如是:插入排序通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入 ,如此重复,直至完成序列排序。

        过程如下面网图,把未点亮的图当作你还没有摸到的牌,当你拿到“牌”时就要在你已经排好的牌中,一张一张地从后往前看,直到找到一张比你小的牌,你就可以安心插入了:

     ------------------------*注意: 为了下文便于理解, “关键位”替换为"牌"    ----------------------------------

二、算法实现

        1.直接插入排序

        遵从上面的思想,我们便来用代码实现一下:

//插入排序
void InsertSort(int* arr, int n)
{
	for (int i = 0; i < n - 1; i++)//第一层循环,保证所有“牌”(数据)都拿到
	{
		int end = i;//每次从已经排好的“牌”(序列)最后一个开始
		int tmp = arr[end + 1];//拿“牌”
		while (end >= 0)//开始从后往前遍历,找比手中"牌"小的
		{
			if (tmp < arr[end])//比手中“牌”大的,往后挪
			{
				arr[end+1] =arr[end];
				end--;
			}
			else
			{
				break;//找的比手中“牌”小的,不找了
			}
		}
		arr[end + 1] = tmp;//插在比手中“牌”小的后面
	}
}

        下面看看该代码的效果

        输入:

        

        输出:

          

       2.二分插入排序

        上个方法,虽然说完成了任务,但是各位没有觉得次次都要比较,很累吗?各位真的没有在找比手中“牌”小的牌时想到二分查找吗?没错二分插入排序就是将查找部分改为了二分查找,形成了直接插入排序的变种-二分插入排序。

        代码实现如下:

// 二分插入排序
void BinInsertSort(int* a, int n)
{
	for (int i = 0; i < n-1; i++)
	{
		int left = 0;
		int right = i;
		int temp = a[i+1];
		while (left <= right)//"="为了得出“牌”最终的位置
		{
			int mid = (left + right) / 2; //二分区域
			if (a[mid] > temp)
			{
				right = mid-1;       //向左缩小区域
			}
			else
			{
				left = mid+1;        //向右缩小区域
			}
		}

		for (int j = i+1; j > left; j--)  //vi[left,i-1]的元素整体后移
		{
				a[j] = a[j-1];
		}
		a[right+1] = temp;
		}
}

         输入:

                

        输出:

                

         需要注意的是,当left与right相等时,并不是找到了比手中牌小的位置,而是找到了一个合适的位置,只有在进行一次比较,才能确定牌的位置,所以在第一层循环时的条件加了“=”

        如下图:

         同理,当“牌”换成10时,right不会动,a[right+1],"牌"依旧处于原位置。

三、性能分析

         1 时间复杂度:
        (1)顺序排列时,只需比较(n-1)次,插入排序时间复杂度为O(n);
        (2)逆序排序时,需比较n(n-1)/2次,插入排序时间复杂度为O(n^2);
        (3)当原始序列杂乱无序时,平均时间复杂度为O(n^2)。
        2 空间复杂度:
           插入排序过程中,只需要一个临时变量temp存储待排序元素,因此空间复杂度为O(1)。
        3 算法稳定性:
           插入排序是一种稳定的排序算法。


        *注意:二分插入仅供思路,所以未加入分析

        

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值