算法 ——插入排序(直接插入排序,希尔排序)的基本思想和解析

Posted 努力学习的少年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法 ——插入排序(直接插入排序,希尔排序)的基本思想和解析相关的知识,希望对你有一定的参考价值。

1.插入排序

插入排序的基本思想:

插入排序是一种最简单的的排序思想,它的思想是将一个数据插入到一个有序的数据列表,得到一个新的有序列表。

 插入排序类型于将我们完的扑克,将牌一张一张插入到我们的序列中,形成一个有序的序列。

 

 整形数组 9  1  2  5  7 4插入排序的过程。蓝色箭头指向的值为tmp值。紫色箭头是tmp插入的位置。

 

 

 

       插入排序 对应的代码:

void Insert(int arr[], int n)
{
	for (int i = 0; i < n; i++)//进行插入排序的次数
	{
		int end = i;//指向有序序列结尾的指针
		int tmp = arr[end];//蓝色箭头指向的值
		while (end - 1 >= 0 && arr[end - 1] > tmp)
		{
			arr[end] = arr[end - 1];//将数据后移
			end--;
		}
		arr[end] = tmp;//将数据插入到正确的位置上
	}
}

 插入排序的时间复杂度:

当一个序列是完全有序的时候,例如序列为1  2  3  4  5 .....,那么只需遍历一遍序列, 此时的插入排序时间复杂度为O(N),所以当序列越接近有序的时候,时间复杂度就越接近O(N);如果一个序列是完全逆序的时候,例如序列 5 4 3 2 1 .....,那么每次遍历的时候都需要将数据插入到前面时间复杂度为O(N^2),但由于时间复杂度是按最坏的情况去考虑的,所以插入排序的时间复杂度为O(N^2).

 2.希尔排序

   希尔排序又称“缩小增量排序”,它也是一种插入排序的方法,但在时间效率比直接插入排序要好很多。

它的基本思想是:先将整个待排序列分成若干子序列分别进行直接插入排序,待整个序列中记录”基本有序时“在对整个序列进行一次直接插入排序

我们以数组中 9  1  2  5  7   4  8  6  3  5来看一下希尔排序是怎样的把这个数组排成一个有序的。

 

 

 其中的gap为每一趟中的子序列之间的间隔,对每一个子序列进行插入排序,当一趟排序完成后,就进行下一趟排序,gap就不断缩小,则序列也不断的接近有序,当gap减到为1时并且排序完成后则整个序列就为有序的。当gap很大时,则序列就排序的很快,当gap很小时,则排出的序列就接近有序。当gap为1时相当于插入排序,此时序列已经接近有序了,所以该插入排序的时间复杂度接近O(n). 

插入排序的代码:

//希尔排序
void ShellSort(int arr[], int n)
{
	  int gap = n ;//gap为个子序列的间隔
	  while (gap > 1)
	  {
		  gap = gap / 3 + 1;//不断缩小gap
	 
	 for (int i = 0; i < n - gap; i++)//进行每一趟的排序
	 {
		 int end = i;//每一趟中子序列的插入排序
		 //对子序列中数据进行插入排序
		 int tmp = arr[end + gap];
		 while (end >= 0 && arr[end] > tmp)
		 {
		    arr[end + gap] = arr[end];
			end -= gap;
		 }
	    arr[end + gap] = tmp;
	 }
	}
 }

希尔排序代码解析:

1.gap=gap/3+1,

每一趟的gap都不断缩小3倍,加上1是防止最后一趟的gap为0,因为最后第二趟gap为2时,则最后一趟除3为2/3就为0;

2.

         int end = i;
         int tmp = arr[end + gap];
         while (end >= 0 && arr[end] > tmp)
         {
            arr[end + gap] = arr[end];
            end -= gap;
         }
        arr[end + gap] = tmp;

为每一趟中的子序列的插入排序,子序列中的间隔为gap,移动都是往后挪动gap的位置。

对应下面子序列的插入过程。类型插入排序,只是每个数据的间隔变为gap。插入排序的gap为

 

 3.for (int i = 0; i < n - gap; i++)

因为我们要对每个子序列中进行插入排序,使每个子序列都有序,这时我们遍历整个序列,当i指向哪一个值后,我们就浮现i相对应的子序列,在子序列中,我们将i后一位的值插入到有序的子序列中,当i到排n-gap后就终止。如下图所示。

 希尔排序的时间复杂度:

希尔排序中的分析是一个复杂的问题。因为它的时间复杂度是所取”增量“序列的函数,这涉及一些数学上尚未研究的难题,到目前为止尚未有人求得一种最好的增量序列,但大量的研究已经推出它的时间复杂度为O(n^(3/2) )

我们可以大概计算希尔排序最坏的时间复杂度:

先算for循环的时间复杂度,

当gap很大的时候,里面的while循环几乎不计为,所以for循环为O(N),

.......

当gap越来越小时,本来是插入排序的,但由于序列中已经接近有序,所以插入排序接近O(N)

再算 while (gap > 1)的时间复杂度

n/3/3/3/3...=1

3^x=n ,x是循环的次数,所以while的时间复杂度为O(log3 n)

所以希尔排序的最坏的时间复杂度大概是O(( log3 n) *n),相较于插入排序,这个算法算快的。

以上是关于算法 ——插入排序(直接插入排序,希尔排序)的基本思想和解析的主要内容,如果未能解决你的问题,请参考以下文章

算法3 七大排序之:直接插入排序和希尔排序

算法 ——插入排序(直接插入排序,希尔排序)的基本思想和解析

排序算法3--插入排序--希尔排序(缩小增量排序)

算法拾遗(java描写叙述)--- 插入排序(直接插入排序希尔排序)

算法 希尔排序

算法 希尔排序