插入排序与希尔排序详解

﹥>﹥吖頭↗ 提交于 2020-02-08 19:14:44

插入排序

插入排序(Insertion sort)是一种简单直观且稳定的排序算法。有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法——插入排序法,插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。

(摘自百度百科,黑体部分定义在很多博文中都有看到,但基本未见在代码中体现。博主认为是望文生义的概率比较大,所以以下面维基百科的定义为准)

维基百科:

插入排序工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间

算法描述如下:

1.从第一个元素开始,该元素可以认为已经被排序
2.取出下一个元素,在已经排序的元素序列中从后向前扫描
3.如果该元素(已排序)大于新元素,将该元素移到下一位置
4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
5.将新元素插入到该位置后
6.重复步骤2~5

如下图所示:
在这里插入图片描述

希尔排序

希尔排序(Shellsort),也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:

1.插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
2.但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位

工作原理:
首先把数据元素根据增量即gap分割成若干个小组(逻辑上分组),然后对每一个小组分别进行插入排序,此时,插入排序所作用的数据量比较小(每一个小组),插入的效率比较高。然后缩小gap的值继续进行排序。直到gap=1。
在这里插入图片描述

首先,选择增量 gap = 10/2 ,缩小增量继续以 gap = gap/2 的方式

初始增量为 gap = 10/2 = 5,整个数组分成了 5 组按颜色划分为

【 8 , 3 】,【 9 , 5 】,【 1 , 4 】,【 7 , 6 】,【 2 , 0 】

对这分开的 5 组分别使用

上节所讲的插入排序

结果可以发现,这五组中的相对小元素都被调到前面了

缩小增量 gap = 5/2 = 2,整个数组分成了 2 组

【 3 , 1 , 0 , 9 , 7 】,【 5 , 6 , 8 , 4 , 2 】

对这分开的 2 组分别使用上节所讲的插入排序此时整个数组的有序性是很

明显的再缩小增量 gap = 2/2 = 1,整个数组分成了 1 组

【 0, 2 , 1 , 4 , 3 , 5 , 7 , 6 , 9 , 0 】

此时,只需要对以上数列进行简单的微调,不需要大量的移动操作即可完

成整个数组的排序
图文引用出处
链接:https://www.jianshu.com/p/40dcc3b83ddc

算法分析:
希尔排序的时间的时间复杂度为O( ),希尔排序时间复杂度的下界是n*log2n。希尔排序没有快速排序算法快 O(n(logn)),因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择。但是比O( )复杂度的算法快得多。并且希尔排序非常容易实现,算法代码短而简单。 此外,希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏的情况下执行的效率会非常差。专家们提倡,几乎任何排序工作在开始时都可以用希尔排序,若在实际使用中证明它不够快,再改成快速排序这样更高级的排序算法. 本质上讲,希尔排序算法是直接插入排序算法的一种改进,减少了其复制的次数,速度要快很多。 原因是,当n值很大时数据项每一趟排序需要移动的个数很少,但数据项的距离很长。当n值减小时每一趟需要移动的数据增多,此时已经接近于它们排序后的最终位置。 正是这两种情况的结合才使希尔排序效率比插入排序高很多。

vs下编译通过
head.h

#ifndef HEAD_H
#define HEAD_H
#include<iostream>
#include<time.h>
#include <iomanip>

using namespace std;
#define Maxsize 30

void Array_generate(int a[], int len);
void Insertion_Sort(int a[], int len);
void Shell_Sort(int a[], int len);
void Print(int a[], int len);

operation.cpp

#include"head.h"
void Array_generate(int a[], int len)
{
	srand(time(NULL));
	for (int i = 0;i < len;i++)
	{
		a[i] = rand() % 100;
	}
	for (int j = 0;j < len;j++)
	{
		cout << setw(3) << a[j];
	}
	cout << endl;
}
void Insertion_Sort(int a[], int len)
{
	int i, j, temp;                //前插法
	for (i = 1; i < len; i++) {   //(i=1)将序列的第一个数据看成是一个有序的子序列,然后从第二
								 //个数据逐个向该有序的子序列进行有序的插入,直至整个序列有序
		temp = a[i];
		for (j = i; j > 0; j--) {          // 从后向前比较
			if (a[j - 1] > temp)          //如果a[j]前面的数比它大
				a[j] = a[j - 1];          // 将大数向后移动
			else      break;              //插入完成跳出循环
		}
		a[j] = temp;  //完成插入操作
	}
}
void Shell_Sort(int a[], int len)
{

	for (int gap = len / 2;gap > 0;gap /= 2)//只需要在外层加一层控制增量的循环即可
	{
		Insertion_Sort(a, len);
	}
}
void Print(int a[], int len)
{
	int i = 0;
	for (i;i < len;i++)
	{
		cout << setw(3) << a[i];
	}
	cout << endl;
}

mian.cpp

#include "head.h"


int main()
{
	int  len;
	int a[Maxsize];
    cout << "输入数组元素个数" << endl;
	cin  >> len ;
	cout << endl;
	cout << "生成一个元素个数为"<<len<<"的随机数组"<<endl;
	Array_generate(a, len);
	cout << endl;
	cout << "插入排序:" << endl;
	Insertion_Sort(a, len);
	Print(a, len);
	cout << endl;
	
	cout << "输入数组元素个数" << endl;
	cin >> len;
	cout << endl;
	cout << "生成一个元素个数为" << len << "的随机数组" << endl;
	Array_generate(a, len);
	cout << endl;
	cout << "希尔排序:" << endl;
	Shell_Sort(a, len);
	Print(a, len);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!