您的位置:首页 > 其它

排序算法之直接插入排序与希尔排序

2017-07-09 08:37 393 查看


排序算法之直接插入排序和希尔排序

直接插入排序

直接插入排序是稳定的排序方法。直接插入排序的基本思想:假设待排序的记录存放在数组R[1...n]中。初始时,R[1]自成一个有序区,无序区为R[2...n]。从i=2起直至i=n为止,依次将R[i]插入当前的有序区R[1...i-1]中,生成含n个记录的有序区。

第i-1趟直接插入排序:

通常将一个记录R[i] (i=2, ..., n-1) 插入到当前的有序区,使得插入后仍保证该区间里的记录是按关键字有序的操作,称为第i-1趟直接插入排序。

排序过程中的某一中间时刻,R被划分成两个子区间:R[1...i-1] (已排序好的有序区) 和 R[i...n] (当前未排序的部分, 可称为无序区)。

直接插入排序的基本操作是将当前无序区的第一个记录R[i]插入到有序区R[1...i-1]中适当的位置上,使R[1...i]变为新的有序区。因为这种方法每次使有序区增加一个记录,通常称为增量法。

插入排序与打扑克时整理手上的牌非常类似。摸来的第一张牌无须整理,此后每次从桌上的牌中模最上面的一张并插入左手的牌中正确的位置上。为了找到这个正确的位置,须自左向右(或自右向左)将摸来的牌与左手中已有的牌逐一比较。

由直接插入排序的基本思想很容易得到下面简单的方法。

(1) 在当前有序区R[1...i-1]中查找R[i]的正确位置k(1<=k<=i-1)。

(2) 将R[k...i-1]中的记录均后移一个位置,腾出k位置上的空间插入R[i]。

这里我们使用升序排序,也就是说,如果R[i]的关键字大于等于R[1...i-1]中所有记录的关键字,则R[i]就是插入地位置。

还有一种改进的方法,即查找比较操作和记录移动操作交替进行。其具体的做法如下。

将待插入记录R[i]的关键字从右向左依次与有序区中记录R[j] (j=i-1,i-2,...,1)的关键字进行比较:

(1) 如果R[j]的关键字大于R[i]的关键字,则将R[j]后移一个位置;

(2) 如果R[j]的关键字小于或等于R[i]的关键字,则查找过程结束,j+1即为R[i]的插入位置。

关键字比R[i]的关键字大的记录均已后移,所以j+1的位置已经腾空,只要将R[i]直接插入此位置即可完成一趟直接插入排序。

希尔(shell)排序

希尔(Shell)排序是D.L.shell 于1959年提出的,它属于插入排序方法,是不稳定的排序方法。

我们知道,在直接插入排序算法中,每次插入一个数,使有序序列只增加一个节点,并且对插入下一个数没有提供任何帮助。如果比较相隔较远距离(称为增量)的数,使得数移动能跨过多个元素,则进行一次比较就可能消除多个元素的交换。

希尔(Shell)排序算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差对新租重新进行排序。当增量减到1时,整个排序的数被分成一组,排序完成。因此,希尔排序实质上是一种分组插入方法。

希尔排序的实践性嫩优于直接插入排序,其原因如下:

(1) 当数组初始状态基本有序时,直接插入排序所需的比较和移动次数均较少。

(2) 当n值较小时,n和n2的差别也较小,即插入排序的最好时间复杂度O(n)和最坏时间复杂度O(n2)差别不大。

(3) 在希尔排序开始时,增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量d逐渐减小,而各组的记录数目逐渐增多。但由于已经按d-1作为距离排过序,数组较接近于有序状态,所以新的一趟排序过程也较快。

因此,希尔排序在效率上较直接插入排序有较大的改进。

另外,由于分组的存在,相等的元素可能会分在不同组,导致它们的次序可能发生变化,因此希尔排序是不稳定的。

代码:

/***************************
* Straight Insertion Sort
*
*  By chyeer 2017/07/08
*
* ************************/

#include
#include

using namespace std;

//Stable Sort
void InsertionSort(int a[], int n){
int i, j, tmp;
for(i=1; i=0&&tmp0; h/=2){ // decrease the increment.
for(i=h; i=0&&tmp

运行结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐