首页 > 代码库 > 排序——希尔排序

排序——希尔排序

    希尔排序(Shell Sort)是插入排序的一种。是针对直接插入排序算法的改进。该方法又称缩小增量排序,因DL.Shell于1959年提出而得名。
基本思想:
    先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
希尔排序的实现代码:
#include <iostream>   
using namespace std;  

void print(int a[], int n ,int i)
{  
    cout<<"处理a["<<i<<"]"<<": ";  
    for(int j= 0; j<8; j++)
	{  
        cout<<a[j]<<" ";  
    }  
    cout<<endl;
}  
      
void shell_sort(int a[], int n)  
{  
    int i, j, temp, dk;

	dk = n;
	while((dk/=2) > 0)
	{
		cout<<"步长为"<<dk<<"时候的排序过程:"<<endl;
		for(i=dk; i < n; ++i) /*默认开始的时候前面是一个排好序的序列,开始时默认前面一个数是排好序*/
		{  
			if(a[i] < a[i-dk]) /*需要插入的元素与排好序的序列最后一个元素做比较*/
							   /*只有不满足大小关系时才到序列中查找插入位置*/
			{                      
				temp = a[i]; /*复制为哨兵,即存储待插入元素*/ 
				a[i] = a[i-dk]; /*首先后移一个元素*/
				j = i - dk; 
				while(j>=0 && temp<a[j]) /*查找在有序表的插入位置,注意数组越界的判断*/
				{   
					a[j+dk] = a[j]; /*元素后移*/
					j -= dk;        
				}  
				a[j+dk] = temp; /*插入到正确位置*/  
			}  
			print(a, n, i);  
		}
	}
      
}  
       
int main()
{  
    int a[8] = {3, 1, 5, 7, 2, 4, 9, 6};
	int i;

	cout<<"初始序列: ";
	for(i=0; i < sizeof(a)/sizeof(int); i++)
		cout<<a[i]<<" ";
	cout<<endl;
    shell_sort(a, sizeof(a)/sizeof(int)); /*希尔插入排序*/  
}  
程序运行效果截图:

希尔排序算法的特点:
    希尔排序是基于插入排序的一种算法, 在此算法基础之上增加了一个新的特性,提高了效率。希尔排序的时间复杂度与增量序列的选取有关,例如希尔增量时间复杂度为O(n^2),而Hibbard增量的希尔排序的时间复杂度为O(n^(3/2)),但是现今仍然没有人能找出希尔排序的精确下界。希尔排序没有快速排序算法快 O(n(logn)),因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择。但是比O(n^2)复杂度的算法快得多。并且希尔排序非常容易实现,算法代码短而简单。 此外,希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏的情况下执行的效率会非常差。专家们提倡,几乎任何排序工作在开始时都可以用希尔排序,若在实际使用中证明它不够快,再改成快速排序这样更高级的排序算法. 本质上讲,希尔排序算法是直接插入排序算法的一种改进,减少了其复制的次数,速度要快很多。 原因是,当n值很大时数据项每一趟排序需要的个数很少,但数据项的距离很长。当n值减小时每一趟需要和动的数据增多,此时已经接近于它们排序后的最终位置。 正是这两种情况的结合才使希尔排序效率比插入排序高很多。
希尔排序算法的空间复杂度:O(1),只需要一个辅助单元来完成数据的交换。
希尔排序算法的稳定性:稳定。
稳定性定义:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。