您现在的位置是:首页 >学无止境 >排序算法——直接插入排序网站首页学无止境

排序算法——直接插入排序

Forward♞ 2024-08-07 18:01:01
简介排序算法——直接插入排序

直接插入排序

基本思想

  • 直接插入排序是一种简单明了的插入排序法,其基本思想是:把待排序的数据按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有数据插入完为止。

  • 在现实生活中,我们玩扑克对牌进行排序就运用了这种思想。

    在这里插入图片描述

整体插入思想

统一使用升序

  • 当插入第(i >= 1)个元素时,前面的array[0], array[1], ……, array[i - 1]已经有序,此时用array[i]的值与array[i - 1], array[i - 2],……的值顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移。

  • 如对数组{2, 5, 4, 6, 8, 7, 1}进行升序排序

    在这里插入图片描述

代码实现

  • 我们假设数组中[0,end]的数据已经有序,要将nums[end + 1]这个元素插入到[0,end]中,使[0,end + 1]也有序

  • 因为可能要进行数据后移的操作,为防止nums[end + 1]被覆盖而无法得到其值,要事先用临时变量保存

    int end;
    int temp = nums[end + 1];	
    
  • 运用插入排序的思想,将nums[end + 1](即temp)从后往前依次与有序的元素进行比较,满足条件就插入

    while (end >= 0)
    {
        /*
        	如果后面的数比前面的小,那就将前面的数后移
        	继续将后面的数与更前面的数(即更小的数)比较
        */
        if (temp < nums[end])
        {
            nums[end + 1] = nums[end];
            end--;
        }
        /*
        	否则,如果后面的数比前面的大
        	那么满足升序条件,将temp插入到nums[end]的后面
        */
        else
            nums[end + 1] = temp;
    }
    
  • 但是,上面这段代码还是存在一个小小的bug,即如果我们要插入的元素temp比有序序列的第一个元素nums[0]还要小,那么执行完 nums[end + 1] = nums[end];end--;这一操作后,end就等于-1了,而循环的条件是end >= 0,无法进入循环,end[0]这一位置也无法被赋值,因此,我们要进行改进:

    while (end >= 0)
    {
        if (temp < nums[end])
        {
            nums[end + 1] = nums[end];
            end--;
        }
        
        /*
        	如果后面的数比前面的大
        	那么满足升序条件,直接退出循环
        */
        else
            break;
    }
    
    //将(end >= 0 && temp > nums[end])和 (end == -1)这两种情况整合到一起
    nums[end + 1] = temp;
    
  • 设待排序数组有numsSize个元素,因此要使数组有序,就要用一层for循环来分别判断数组的每个值是否处于正确的位置。

    //为防止数组越界,i的最大值为numsSize - 2
    for (int i = 0; i < numsSize - 1; i++)
    {
        int end = i;
    	int temp = nums[end + 1];
        …………
    }
    

实现代码

void InsertSort(int* nums, int numsSize)
{
    //为防止数组越界,i的最大值为numsSize - 2
	for (int i = 0; i < numsSize - 1; i++)
	{
		/*
			假设[0,end]已经有序
			要将nums[end + 1]这个元素插入到[0,end]中,使[0,end + 1]也有序
		*/
		int end = i;
		int temp = nums[end + 1];	//因为可能要进行数据后移的操作,为防止nums[end + 1]被覆盖而无法得到其值,要事先用临时变量保存	
        
		while (end >= 0)
        {
            if (temp < nums[end])
            {
                nums[end + 1] = nums[end];
                end--;
            }

            /*
                如果后面的数比前面的大
                那么满足升序条件,直接退出循环
            */
            else
                break;
        }

        //将(end >= 0 && temp > nums[end])和 (end == -1)这两种情况整合到一起
        nums[end + 1] = temp;
    }
}

时间复杂度

统一为升序排序

  • 最好的情况:最好的情况就是数组已经升序有序,只有最外面一层for循环遍历一次数组,里面的while循环每一次都是直接退出,因此最好的情况时间复杂度为O(N)
  • 最坏的情况:最坏的情况就是数组是降序排序,里面while循环的时间复杂度为O(N),因此最坏情况下,时间复杂度为O(N2)
  • 综上,直接插入法的时间复杂度为O(N2)
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。