Fork me on GitHub

希尔排序

--------------------siwuxie095

   

   

   

   

   

   

希尔排序法

   

   

它的工作原理如下:

   

初期选用大跨步(增量较大)间隔比较,使记录跳跃式接近

它的排序位置;然后增量缩小;最后增量为 1 ,这样记录移

动次数大大减少,提高了排序效率

   

   

参考链接:

参考链接1参考链接2参考链接3

   

   

   

   

   

程序 1:希尔排序法的实现

   

SortTestHelper.h:

   

#ifndef SORTTESTHELPER_H

#define SORTTESTHELPER_H

   

#include <iostream>

#include <string>

#include <ctime>

#include <cassert>

using namespace std;

   

   

//辅助排序测试

namespace SortTestHelper

{

   

//生成测试数据(测试用例),返回一个随机生成的数组:

//生成有n个元素的随机数组,每个元素的随机范围为[rangeL,rangeR]

int *generateRandomArray(int n, int rangeL, int rangeR)

{

//默认rangeL要小于等于rangeR

assert(rangeL <= rangeR);

   

int *arr = new int[n];

   

//对于数组中的每一个元素,将之随机成为rangeLrangeR之间的随机数

//先设置随机种子:这里将当前的时间作为种子来进行随机数的设置

srand(time(NULL));

   

for (int i = 0; i < n; i++)

{

//rand()函数+百分号+数的范围,即取中间的一个随机整数,再加上rangeL即可

arr[i] = rand() % (rangeR - rangeL + 1) + rangeL;

}

return arr;

}

   

   

//生成一个近乎有序的数组

int *generateNearlyOrderedArray(int n, int swapTimes)

{

//先生成完全有序的数组

int *arr = new int[n];

for (int i = 0; i < n; i++)

{

arr[i] = i;

}

   

//以当前时间为随机种子

srand(time(NULL));

   

//再随机挑选几对元素进行交换,就是一个近乎有序的数组了

for (int i = 0; i < swapTimes; i++)

{

int posx = rand() % n;

int posy = rand() % n;

swap(arr[posx], arr[posy]);

}

   

return arr;

}

   

   

template<typename T>

void printArray(T arr[], int n)

{

for (int i = 0; i < n; i++)

{

cout << arr[i] << " ";

}

cout << endl;

}

   

   

//经过排序算法排序后,再次确认是否已经完全排序

template<typename T>

bool isSorted(T arr[], int n)

{

for (int i = 0; i < n - 1; i++)

{

if (arr[i]>arr[i + 1])

{

return false;

}

}

return true;

}

   

   

//衡量一个算法的性能如何,最简单的方式就是看这个算法在特定数据集上的执行时间

//1)传入排序算法的名字,方便打印输出

//2)传入排序算法本身,即函数指针

//3)传入测试用例:数组和元素个数

template<typename T>

void testSort(string sortName, void(*sort)(T[], int), T arr[], int n)

{

//在排序前后分别调用clock()函数

//时间差就是该排序算法执行的时钟周期的个数

clock_t startTime = clock();

sort(arr, n);

clock_t endTime = clock();

   

assert(isSorted(arr, n));

   

//endTime 减去 startTime 转为double类型,除以 CLOCKS_PER_SEC,其中:

//

//CLOCKS_PER_SEC 是标准库中定义的一个宏,表示每一秒钟所运行的时钟周期

//的个数,而(endTime-startTime)返回的是运行了几个时钟周期

//

//这样,最终的结果就是在这段时间中程序执行了多少秒

cout << sortName << "" << double(endTime - startTime) / CLOCKS_PER_SEC

<< "s" << endl;

}

   

   

//复制数组

int *copyIntArray(int a[], int n)

{

int *arr = new int[n];

//copy()函数在std中:

//第一个参数是原数组的头指针,

//第二个参数是原数组的尾指针,

//第三个参数是目的数组的头指针

//

//注意:copy()函数运行时会报错,需要在:

//项目->属性->配置属性->C/C++->预处理器->预处理器定义

//在其中添加:_SCL_SECURE_NO_WARNINGS

copy(a, a + n, arr);

return arr;

}

}

   

#endif

   

   

   

ShellSort.h:

   

#ifndef SHELLSORT

#define SHELLSORT

   

   

//希尔排序:从小到大进行排序

template<typename T>

void shellSort(T arr[], int n)

{

   

int i, h;

   

// h为步长,每次减为原来的一半。

for (h = n / 2; h > 0; h /= 2)

{

// h个组,对每一组都执行直接插入排序

for (i = h; i < n; i++)

{

T e = arr[i];

int j;

for (j = i; j >= h && e < arr[j - h]; j -= h)

{

arr[j] = arr[j - h];

}

arr[j] = e;

}

}

}

   

   

//通过插入排序,可以引申出一种非常重要的排序算法,叫做希尔排序

//

//希尔排序整体的思路就是插入排序的延伸

//

//在插入排序中,每一次都和之前的一个元素进行比较

//

//而希尔排序每一次尝试和之前第h个元素进行比较,这样下来,通过将这个h

//从一个很大的值逐渐缩小到1,一步一步的将一个完全无序的数组,变成近乎

//有序的数组,或变成有序性更强的数组,最后当h等于1时,最终变成了一个

//排好序的数组,这个过程使得整个算法的时间复杂度发生了质变

//

//希尔排序的时间复杂度是 O(n^3/2),即 n 的二分之三次方

   

#endif

   

   

   

main.cpp:

   

#include "SortTestHelper.h"

#include "ShellSort.h"

   

   

int main()

{

   

int n = 10000;

   

int *arr = SortTestHelper::generateRandomArray(n, 0, n);

 

SortTestHelper::testSort("Shell Sort", shellSort, arr, n);

//SortTestHelper::printArray(arr, n);

 

delete []arr;

 

system("pause");

return 0;

}

   

   

运行一览:

   

   

   

   

   

   

   

   

程序 2:希尔排序法的优化(在程序 1 的基础上,修改 ShellSort.h 即可)

   

ShellSort.h:

   

#ifndef SHELLSORT

#define SHELLSORT

   

   

//希尔排序:从小到大进行排序

template<typename T>

void shellSort(T arr[], int n)

{

   

int h = 1;

while (h < n / 3)

{

h = 3 * h + 1;

// 计算 increment sequence: 1, 4, 13, 40, 121, 364, 1093...

}

   

   

while (h >= 1)

{

   

// h-sort the array

for (int i = h; i < n; i++)

{

   

// arr[i], arr[i-h], arr[i-2*h], arr[i-3*h]... 使用插入排序

T e = arr[i];

int j;

for (j = i; j >= h && e < arr[j - h]; j -= h)

{

arr[j] = arr[j - h];

}

arr[j] = e;

}

   

h /= 3;

}

}

   

   

//通过插入排序,可以引申出一种非常重要的排序算法,叫做希尔排序

//

//希尔排序整体的思路就是插入排序的延伸

//

//在插入排序中,每一次都和之前的一个元素进行比较

//

//而希尔排序每一次尝试和之前第h个元素进行比较,这样下来,通过将这个h

//从一个很大的值逐渐缩小到1,一步一步的将一个完全无序的数组,变成近乎

//有序的数组,或变成有序性更强的数组,最后当h等于1时,最终变成了一个

//排好序的数组,这个过程使得整个算法的时间复杂度发生了质变

//

//希尔排序的时间复杂度是 O(n^3/2),即 n 的二分之三次方

   

#endif

   

   

运行一览:

   

   

   

   

   

   

   

   

   

【made by siwuxie095】

posted on 2017-05-26 14:17  siwuxie095  阅读(134)  评论(0编辑  收藏  举报

导航