【算法】希尔排序C语言实现

上一篇文章我们一起学习了直接插入排序,它的原理就是把前i个长度的序列变成有序序列,然后循环迭代,直至整个序列都变为有序的.但是说来说去它还是一个时间复杂度为(n^2)的算法,难道就不能再进一步把时间复杂度降低一阶么?可能有很多同学说快速排序,堆排序,我都会,这些简单的插入排序我都不屑于用.确实,以上几种算法相对于之前的O(n^2)级别的算法真的是弱爆了,效率可能还会差上千万倍,但是我们不妨翻看一下历史,你就会感觉每一种算法的出现都是很可贵的.在1959年D.L.Shell正式提出了我们今天的主角shell算法,这是相当酷的一件事情,为什么这么说呢?因为shell排序时第一个突破了O(n^2)时间复杂度的排序算法,这应该是排序算法历史上比较闪耀的时刻了,因为在1959年之前的相当长的一段时间里,各种各样的排序算法无论是怎么花样繁多,都始终无法突破O(n^2)雷池一步,在当时直接插入排序已经是相当优秀的了,而排序算法不可能突破O(n^2)的声音成为了当时的主流.

看见了这段历史之后你有什么感受呢,我们在课堂上不愿意学的算法确仍然是科学家们多年苦苦思索才发明出来的,是不是觉得他们很不容易呢?其实你也没必要内疚啦,即使你曾经对它不屑一顾过,没有认真的学它,So what?现在开始学也不晚是不是?

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

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

其实直接插入排序并不是那么逊的,它在待排序数据基本有序并且数量较少的时候威力还是很大的,甚至比一些高级算法还要高效.对于第二点,我只能说这就是我们shell算法的牛逼的地方了,插入排序每次只能移动数据一位,而shell算法成功的解决了这个问题.

shell算法的核心还是分组,但是这个分组就有门道儿了,因为它会实现取一个小于总数据长度的整数值gap作为分组的步长,什么意思呢?不说我们的待排序数组为49,38,65,97,76,13,27,49,55,04 假如gap的值为长度10的一半也就是5,那么第一个和第六个元素就是一组,第二个和第七个元素就是一组,第三个和第八个元素就是一组,第四个和第九个元素就是一组,第五个和第十个元素就是一组,所以一共分为了gap
= 5组,每一组之间进行再直接插入排序,比较如果前一个元素比较大,则交换两个元素的位置,直至5组全部交换完毕.此时数组的顺序为13   27   49   55   4    49   38   65   97   26.然后gap的值再减半为2,重新分组,也就是第一个 第三个 第五个 第七个 第九个 元素为第一组是13  49  4  38  97, 第二个 第四个 第六个 第八个 第十个元素为一组是
27  55  49  65  26.然后对它们两个组分别进行直接插入排序,得到结果为 4   26   13   27   38    49   49   55   97   65,之后gap的值再减半为1(要知道gap的值小于1的时候在分组就没意义了,一位你的每一个组至少要有一个元素才能组成一个序列.)这次我们直接对上一次的结果进行一次真正的直接插入排序(为什么说是真正的呢,因为此时步长已经为1)直至得出最终结果:4  
13   26   27   38    49   49   55   65   97.

下面是shell算法的实现代码:

void shell_sort(int array[], int length){
	int i;
	int j;
	int k;
	int gap;	//gap是分组的步长
	int temp;	//希尔排序是在直接插入排序的基础上实现的,所以仍然需要哨兵
	for(gap=length/2; gap>0; gap=gap/2){
		for(i=0; i<gap; i++){
			for(j=i+gap; j<length; j=j+gap){	//单独一次的插入排序
				if(array[j] < array[j - gap]){
					temp = array[j];	//哨兵
					k = j - gap;
					while(k>=0 && array[k]>temp){
						array[k + gap] = array[k];
						k = k - gap;
					}
					array[k + gap] = temp;
				}
			}
		}
	}
}

希尔排序的时间复杂度为O(nlogn),这是完全按照希尔算法的思想写的,并没有做任何更改.我在博客上看到过有些大神为了追求代码的"简洁之美",尽量使代码保持最短,(强调一下,如果是为了让算法执行的效率更高的话,我们当然要膜拜)但是这样的话可能就不那么好理解了,会给他人造成困扰,因为并不是每一个人都是对这个算法相当熟稔,新手看了你的代码会很气馁,对自信心也是一种伤害代码毕竟还是要给人看的,我们要不为难别人,这样即节省别人的时间也会节省自己的时间,何乐而不为呢,毕竟我们中的绝大多数人还要在一个团队里混饭吃.一家之言,可能是我层次还比较低,错了就错了,努力学习总是没错的,谢谢大家.

时间: 2024-11-05 21:53:56

【算法】希尔排序C语言实现的相关文章

(转载)经典排序算法-希尔排序

经典排序算法 - 希尔排序Shell sort 希尔排序Shell Sort是基于插入排序的一种改进,同样分成两部分, 第一部分,希尔排序介绍 第二部分,如何选取关键字,选取关键字是希尔排序的关键 第一块希尔排序介绍 准备待排数组[6 2 4 1 5 9] 首先需要选取关键字,例如关键是3和1(第一步分成三组,第二步分成一组),那么待排数组分成了以下三个虚拟组: [6 1]一组 [2 5]二组 [4 9]三组 看仔细啊,不是临近的两个数字分组,而是3(分成了三组)的倍数的数字分成了一组, 就是每

经典排序算法 - 希尔排序Shell sort

经典排序算法 - 希尔排序Shell sort 希尔排序Shell Sort是基于插入排序的一种改进,同样分成两部分, 第一部分,希尔排序介绍 第二部分,如何选取关键字,选取关键字是希尔排序的关键 第一块希尔排序介绍 准备待排数组[6 2 4 1 5 9] 首先需要选取关键字,例如关键是3和1(第一步分成三组,第二步分成一组),那么待排数组分成了以下三个虚拟组: [6 1]一组 [2 5]二组 [4 9]三组 看仔细啊,不是临近的两个数字分组,而是3(分成了三组)的倍数的数字分成了一组, 就是每

算法 希尔排序

希尔排序 Shell Sort 介绍: 希尔排序(Shell Sort)也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本. 该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个"增量"的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序.因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率比直接插入排序有较大提高. 执行流程: 首先

排序算法——希尔排序

希尔排序 希尔排序(Shell Sort)是插入排序的一种.也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本.希尔排序是非稳定排序算法. 该方法因DL.Shell于1959年提出而得名. 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序:随着增量逐渐减少,每组包含的关键词越来越多, 当增量减至1时,整个文件恰被分成一组,算法便终止. 代码实现 void shellsort(int a[],int n) { int gap=0,i=0,temp=0,j=0; for(

算法----希尔排序(shell sort)

在分析插入排序的算法性能的过程时知道,当数组规模较小或者存在较多的有序子序列时,插入排序将会在很短的时间内完成数组的排序,为此可以设计一个单调序列h[n],将数组分为多个小的序列,然后这些小的序列使用插入排序.h[n]={1,4,7,10,13,16,19--,3*x+1}. 算法实现: void sort::shell_sort(int* a, const int n) { int h = 0; while (h<n/3) h = 3*h + 1; while(h>=1) { for(int

排序算法-希尔排序

希尔排序,插入排序的升级排版 先回顾插入排序 1从集合第二个元素开始(外循环开始) 2取出该元素 标记为C 3从该元素开始,向前遍历,如果元素大于C,则该元素向后移动一位(内循环) 4直到找到一个小于或者等于C元素(或者到达集合头部),将C放在这个元素的下一位(或者集合头部) 重复1(注意选取下一个元素)(外循环第一趟完成,进入第二趟循环) 可以发现问题: 数组:  5,1,2,3,4,0,6,7,8,9 按照从小到大排序会使得多个元素交换位子,这是比较消耗性能的,这里使用希尔排序会高效很多 希

经典排序算法--希尔排序

算法简介 希尔排序是1959 年由D.L.Shell 提出来的,相对直接排序有较大的改进.希尔排序又叫缩小增量排序. 白话理解: 我们依然已排队为例,加入队伍中,有一些小个子站在了队伍的后面,而一些大个子又站在了队伍的前面,这是如果再使用插入排序,那就太没有效率了.通常情况下,老师会先看一眼,然后将后面的小个子和前面的大个子互换位置.当这个队伍顺序差距不是特别明显后,再使用插入排序. 但是计算机没办法一眼看出来哪些元素差距比较大,于是我们可以每趟排序,根据对应的增量,将待排序列分割成若干长度为m

常见排序算法-----希尔排序

1 // 原理 :用grap(希尔增量)将大数据组进行分组 对每一组进行排序 2 // 在写算法的时候,可以从第grap(希尔增量)个元素开始比较,每次减少grap 即可与同一组的上个元素进行比较,当遍历完一次后 3 // grap/2,继续循环,直到grap >0; 4 5 // 插入版 6 public static void shellSort(int[] arr) { 7 int grap = arr.length >> 1; 8 9 for (; grap > 0; gr

&lt;排序算法&gt; 希尔排序ShellSort

1.核心思想:希尔排序是插入排序的一种,是直接插入排序的一种改进版本,他们同属于插入排序类.这是一个不稳定的排序算法.采取跳跃分割的策略:将相距某个“增量”的记录组成一个子序列,这样才能保证在子序列内分别进行直接插入排序后得到的结果是基本有序而不是局部有序.2.代码实现: 1 #include<iostream> 2 using namespace std; 3 4 void PrintArr(int arr[],int len); 5 void ShellSort(int arr[],int