• 友链

  • 首页

  • 文章归档
h u a n b l o g
h u a n b l o g

欢

HI,Friend

04月
06
数据结构

插入排序

发表于 2022-04-06 • 字数统计 4225 • 被 476 人看爆

算法思想

插入排序(Insertion Sort)的基本思想是:每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子文件中的适当位置,直到全部记录插入完成为止。
插入排序主要包括:直接插入排序和希尔排序。

直接插入排序

排序思想

假设待排序的记录存放在数组R[1...n]中,在排序过程的某一时刻,R被划分成两个子区间,R[1...i-1]和R[i...n],其中前一个为已排好序的有序区,而后一个为无序区。
初始时,有序区只含有1个元素R[1],无序区为R[2...n]。
排序过程中,只需每次从无序区中取出第一个元素,把它插入到有序区的适当位置,使之成为新的有序区,依次这样经过n-1次插入后,无序区为空,有序区包含全部n个元素,至此排序结束

实例分析

给定一组关键字(46,39,17,23,28,55,18,46),要求按直接插入排序算法给出每一趟排序结果。

解答

排序过程如下
直接插入排序实例分析.png
步骤:
temp为一个哨兵(副本),用于需要移动元素,避免元素移动时被覆盖
默认第一个元素为有序序列,放进哨兵变量
i = 1;设置temp为第一个元素46,将下标为1(39)的元素与前面元素依次进行比较,发现前面元素46比他大,往前移动,发现前面没有元素后,交换双方位置,并设置temp为当前的元素(39),结果为上图i=2
i = 2;查找下标为2(17)的元素与前面元素依次进行比较,比他大的元素往后移,直到前面没有比他大的元素,放置该元素(下标为0),temp设置为当前移动的元素(17),结果为上图i=3
i = 3;查找下标为3的元素(23),将其与前面有序区进行比较,比他大的元素往后移...直到比较完39后(39往后移),没有比他更大的元素了,则原39元素的下标就是他新的下标(2),将其放进去,temp为当前的元素(39),结果为上图i = 4
i = 4;查找下标为4的元素(28),将其与前面有序区进行比较,比他大的元素往后移...直到比较完39后(39往后移),没有比他更大的元素了,则原39元素的下标就是他新的下标(2),将其放进去,temp为当前的元素(39),结果为上图i= 5
i = 5;查找下标为5的元素(55),将其与前面有序区进行比较,发现没有比他大的元素,不动,temp为当前元素(55),结果为上图i = 6
....
直到排序结束

算法描述

/**
* 直接插入排序
* @param array 排序数组
* @param n 数组长度
**/
void InsertSort(int array[], int n)
{
	//对顺序表R做直接插入排序
	int i,j, temp;
	temp = array[0];
	for (i = 1; i < n; i++)             //若R[i].key<R[i],移动
	{
		if (array[i] < array[i - 1]) {
			temp = array[i];              //当前记录复制为哨兵
			for (j = i - 1; j >= 0 && array[j] > temp; j--)      //找插入位置
			{
				array[j + 1] = array[j];        //记录后移
			}
			array[j + 1] = temp;            //R[i]插入到正确位置
		}
	}
}

算法分析

(1)哨兵的作用

算法中引进的附加记录temp称为哨兵(Sentinel),哨兵有两个作用:

  • ①进入查找(插入位置)循环之前,它保存了R[i]的副本,不致于因记录后移而丢失R[i]的内容;
  • ②它的主要作用是:在查拨循环中"监视"下标变量j是否越界。一旦越界(即j = 0),因为temp和自己比较,循环判定条件不成立使得查找循环结束,从而避免了在该循环内的每一次均要检测j是否越界(即省略了循环判定条件"j>=1"),使得测试查找循环条件的时间大约减少了一半。

(2)算法的时间性能分析

对于具有n个记录的文件,要进行n-1趟排序。
各种状态下的时间复杂度:
直接插入排序时间复杂度.png

(3)算法的空间复杂度分析

算法所需的辅助空间是一个监视哨,辅助空间复杂度S(n)=O(1)。是一个就地排序。

直接插入排序过程

希尔排序

排序思想

先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt - 1<... < (d2<L),即所有记录放在同一组中进行直接插入排序为止。该方法实质上是一种分组插入方法。

简述:

  • ①设置增量系列,一般按倍数递减(如下列实例,10个数,增量设置为5、3、1)
  • ②将其按照增量分组(例如:首先5,中间间隔5个元素为一组),不足不分组
  • 分组的元素按照直接插入排序
  • ④第一个增量排序结束后,按照②③进行第二个增量排序,直至排序结束

实例分析

初始关键字序列为(36,25,48,27,65,25,43,58,76,32)。其增量序列的取值依次为5,3,1,排序过程如图所示。

希尔排序实例分析.png

排序过程

希尔排序最重要的是增量
第一轮:增量d = 5

  • 从第一个元素开始,中间间隔5个元素分组(36、25为一组),后面不足间隔5个,不分组,将其按照直接插入排序(36、25交换位置),结果为:25 25 48 27 65 36 43 58 76 32
  • 第一个元素已经排过了,从第二个元素开始,中间间隔5个元素(25、43为一组)进行分组,将其排序,结果为:25 25 48 27 65 36 43 58 76 32
  • 往后推,第三个元素开始,分组为48、58一组,将其排序,结果为:25 25 48 27 65 36 43 58 76 32
  • 往后推,第四个元素开始,分组为27、76一组,将其排序,结果为:25 25 48 27 65 36 43 58 76 32
  • 往后推,第五个元素开始,分组为65、32一组,将其排序,结果为:25 25 48 27 32 36 43 58 76 65
    增量为5的已经排完(上图d = 5),进行下一轮增量排序

第二轮:增量d = 3,当前序列为:25 25 48 27 32 36 43 58 76 65

  • 从第一个元素开始,中间间隔3个元素分组(25、27、43、65为一组),将其按照直接插入排序,无需变动,结果为:25 25 48 27 32 36 43 58 76 65
  • 从第二个元素开始,中间间隔3个元素分组(25、32、58为一组),将其按照直接插入排序,无需变动,结果为:25 25 48 27 32 36 43 58 76 65
  • 从第三个元素开始,中间间隔3个元素分组(48、36、76为一组),将其按照直接插入排序,结果为:25 25 36 27 32 48 43 58 76 65
    增量为3的已经排完(上图d = 3),进行下一轮增量排序

...直到排序结束

算法描述

void ShellSort(int array[], int n)  //希尔排序函数
{
	int i, j, step;
	for (step = n / 2; step > 0; step = step / 2)  //这里的step是根据10个元素这种情况定义的增量
	{
		for (i = 0; i < step; i++)  //i用来每次分割指定的增量,比如:增量为5时,第一次从下标为0开始分割5个,进行排序,下次就从下标为1开始进行分组
		{
			for (j = i + step; j < n; j = j + step)  //数组下标j,用于每次分组的元素,如:第一次分组:0、5、10.....元素,用于排序
			{
				if (array[j] < array[j - step])		//比较大小,下标前面的元素是否大于下面后面的元素
				{
					int temp = array[j];  //将要移动的元素放到temp中
					int k = j - step;	 //记录前一个元素下标,用于后面往前推(直接插入排序思想)	

					while (k >= 0 && temp < array[k])		//将要比较的元素,依次从后往前比较
					{
						array[k + step] = array[k];  //把大的值往后插入
						k = k - step;
					}
					array[k + step] = temp;  //把小的值往前插入
				}
			}
		}
	}
}

算法分析

(1)增量序列的选择

  • ①最后一个增量必须为1;
  • ②应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。

(2)Shell排序的时间性能优于直接插入排序

实验表明,当n较大时,比较和移动的次数约在n1.25到1.6n1.25之间。

(3)算法的空间复杂度分析

算法空间复杂度为O(1)。是一个就地排序。

(4)稳定性

希尔排序是不稳定的。

希尔排序排序过程

参考

dong.x_辛旭东-C++ 希尔排序

分享到:
交换排序
最短路径和拓扑排序
  • 文章目录
  • 站点概览
欢

网红 欢

你能抓到我么?

Email RSS
看爆 Top5
  • mac系统版本与Xcode版本有冲突 4,091次看爆
  • JAVA_HOME环境配置问题 3,741次看爆
  • AssetBundle使用 3,510次看爆
  • VSCode配置C++开发环境 3,264次看爆
  • Lua反射 3,141次看爆

Copyright © 2025 欢 粤ICP备2020105803号-1

由 Halo 强力驱动 · Theme by Sagiri · 站点地图