插入排序(Insertion sort algorithm)

文章参考:

https://www.geeksforgeeks.org/insertion-sort/
B站视频1
B站视频2



1. 算法描述

Description:
Insertion sort is a simple sorting algorithm that works similar to the way you sort playing cards in your hands. The array is virtually split into a sorted and an unsorted part. Values from the unsorted part are picked and placed at the correct position in the sorted part.

Uses:
Insertion sort is used when number of elements is small. It can also be useful when input array is almost sorted, only few elements are misplaced in complete big array.


2. 实现思路

To sort an array of size n in ascending order:

  1. Iterate from arr[1] to arr[n] over the array.
  2. Compare the current element (key) to its predecessor.
  3. If the key element is smaller than its predecessor, compare it to the elements before. Move the greater elements one position up to make space for the swapped element.

Example:
在这里插入图片描述


3. 动图演示

在这里插入图片描述


4. 代码实现

// C program for insertion sort
#include <math.h>
#include <stdio.h>

void InsertionSort(int arr[], int n);
void PrintArray(int arr[], int n, int nth);

/* Function to sort an array using insertion sort*/
void InsertionSort(int arr[], int n)
{
	int i, key, j;
	for (i = 1; i < n; i++) 
    {
		key = arr[i];
		j = i - 1;

		/* Move elements of arr[0..i-1], that are
		greater than key, to one position ahead
		of their current position */
		while (j >= 0 && key < arr[j]) 
        {
			arr[j + 1] = arr[j];
			j--;
		}
		arr[j + 1] = key;
        PrintArray(arr, n, i);
    }
}

// A utility function to print an array of size n
void PrintArray(int arr[], int n, int nth)
{
	int i;
    if(nth)
    {
        printf("第%dth轮插入排序结果如下:\n", nth);
    }
    else
    {
        printf("未排序之前初始状态如下:\n");
    }
	for (i = 0; i < n; i++)
	{
        printf("%d ", arr[i]);
    }
	printf("\n");
}

/* Driver program to test insertion sort */
int main()
{
	int arr[] = { 4, 3, 2, 10, 12, 1, 5, 6 };
	int n = sizeof(arr) / sizeof(arr[0]);
    PrintArray(arr, n, 0);
	InsertionSort(arr, n);
	return 0;
}

程序输出:

未排序之前初始状态如下:
4 3 2 10 12 1 5 6
第1th轮插入排序结果如下:
3 4 2 10 12 1 5 6
第2th轮插入排序结果如下:
2 3 4 10 12 1 5 6
第3th轮插入排序结果如下:
2 3 4 10 12 1 5 6
第4th轮插入排序结果如下:
2 3 4 10 12 1 5 6
第5th轮插入排序结果如下:
1 2 3 4 10 12 5 6
第6th轮插入排序结果如下:
1 2 3 4 5 10 12 6
第7th轮插入排序结果如下:
1 2 3 4 5 6 10 12


5. 性能分析

5.1. 算法性能

在这里插入图片描述

5.2. 时间复杂度 O(n^2)

当数据正序时,执行效率最好,每次插入都不用移动前面的元素,时间复杂度为O(N)。

当数据反序时,执行效率最差,每次插入都要前面的元素后移,时间复杂度为O(N^2)。

所以,数据越接近正序,直接插入排序的算法性能越好

5.3. 空间复杂度 O(1)

由直接插入排序算法可知,我们在排序过程中,需要一个临时变量存储要插入的值,所以空间复杂度为 O(1)

5.4. 算法稳定性

直接插入排序的过程中,不需要改变相等数值元素的位置,所以它是稳定的算法


6. 算法优化

因为是在一个有序序列中查找一个插入位置,所以可以使用二分查找,以减少元素比较次数提高效率。

二分查找是对于有序数组而言的,假设如果数组是升序排序的。那么,二分查找算法就是不断对数组进行对半分割,每次拿中间元素和目标数字进行比较,如果中间元素小于目标数字,则说明目标数字应该在右侧被分割的数组中,如果中间元素大于目标数字,则说明目标数字应该在左侧被分割的数组中。

// C program for implementation of
// binary insertion sort
#include <stdio.h>

int BinarySearch(int a[], int item, int low, int high);
void BinaryInsertionSort(int a[], int n);
void PrintArray(int arr[], int n, int nth);

// A binary search based function
// to find the position
// where item should be inserted
// in a[low..high]
int BinarySearch(int a[], int item, int low, int high)
{
	if (high <= low)
		return (item > a[low]) ? (low + 1) : low;

	int mid = (low + high) / 2;

	if (item == a[mid])
	{
        return mid + 1;
    }

	if (item > a[mid])
	{
        return BinarySearch(a, item, mid + 1, high);
    }
	return BinarySearch(a, item, low, mid - 1);
}

// Function to sort an array a[] of size 'n'
void BinaryInsertionSort(int a[], int n)
{
	int i, loc, j, selected;

	for (i = 1; i < n; ++i)
	{
		j = i - 1;
		selected = a[i];

		// find location where selected should be inseretd
		loc = BinarySearch(a, selected, 0, j);

		// Move all elements after location to create space
		while (j >= loc)
		{
			a[j + 1] = a[j];
			j--;
		}
		a[j + 1] = selected;
        PrintArray(a, n, i);
	}
}
// A utility function to print an array of size n
void PrintArray(int arr[], int n, int nth)
{
	int i;
    if(nth)
    {
        printf("第%dth轮插入排序结果如下:\n", nth);
    }
    else
    {
        printf("未排序之前初始状态如下:\n");
    }
	for (i = 0; i < n; i++)
	{
        printf("%d ", arr[i]);
    }
	printf("\n");
}
// Driver Code
int main()
{
	int a[] = { 37, 23, 0, 17, 12, 72, 31, 46, 100, 88, 54 };
	int n = sizeof(a) / sizeof(a[0]);
    PrintArray(a, n, 0);
	BinaryInsertionSort(a, n);
	return 0;
}

程序输出:

未排序之前初始状态如下:
37 23 0 17 12 72 31 46 100 88 54
第1th轮插入排序结果如下:
23 37 0 17 12 72 31 46 100 88 54
第2th轮插入排序结果如下:
0 23 37 17 12 72 31 46 100 88 54
第3th轮插入排序结果如下:
0 17 23 37 12 72 31 46 100 88 54
第4th轮插入排序结果如下:
0 12 17 23 37 72 31 46 100 88 54
第5th轮插入排序结果如下:
0 12 17 23 37 72 31 46 100 88 54
0 12 17 23 31 37 46 72 100 88 54
第8th轮插入排序结果如下:
0 12 17 23 31 37 46 72 100 88 54
第9th轮插入排序结果如下:
0 12 17 23 31 37 46 72 88 100 54
第10th轮插入排序结果如下:
0 12 17 23 31 37 46 54 72 88 100

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值