// 05_谢尔排序(Shell's Sort).cpp
/**
* -> Shellsort
* 1. 谢尔排序可以看作是一种插入排序的扩展方法
* 2. 与插入排序法相同的是,它们都是可以看作是一个个新的元素插入到已排好的数组里面的
* 3. 不同点是,在普通的插入排序法中,它是一个个元素比较,也可以理解成,它每个元素与元素间比较的步进是1
* 而在Shell's Sort中,相对多了一个步骤,改了一个步骤,
* 其实两个合起来的改动就是多了一个概念,一个分治的概念,
* 从代码实现的角度来看的话,就是多了一个调整步进的变量。
**/
#include <iostream>
#include <vector>
#include <conio.h> // _getch();
using std::cin; // using 声明
using std::cout;
using std::endl;
using std::vector;
// ________________________ 主函数 _______________________________
int main()
{
void InsertArr(vector<double> & test);
void ShellSort(vector<double> & test);
void ShowArr(vector <double> & test);
bool testagain(true);
char testagainjudge;
vector<double> testArr; // 用于测试的数组
do
{
cout << "------------------------- 现在开始数组的插入排序测试 ---------------------------\n";
cout << " -> 说明:该测试共分为三个步骤:输入 -> (系统内部)排序 -> 输出显示.\n"
<< "-> 注意:在输入时,请按任意字母结束输入。\n";
// 插入
InsertArr(testArr);
ShowArr(testArr);
cout << endl;
// 排序
ShellSort(testArr);
ShowArr(testArr);
cout << endl;
cout << "-> 如需重新测试,请按字符'a',否则请按任意键退出...";
testagainjudge = _getch();
if (testagainjudge == 'a')
{
cin.sync();
testArr.clear();
testagain = true;
system("cls");
}
else
{
testagain = false;
}
}while (testagain);
return 0;
}
/**
* 子程序名称:InsertArr
* 子程序返回类型:void
* 子程序入口参数:vector<double> &
* 子程序功能:由用户设定N个数值,并由用户输入这N个数值,程序将其保存入vector<double>入口参数处。
**/
void InsertArr(vector<double> & test)
{
cout << "-> 请输入需要输入的数值个数:";
unsigned int n;
cin >> n;
cout << "-> 现在开始数值输入(请以空格间开):";
for ( unsigned int i = 0; i < n; ++i)
{
double value;
cin >> value;
while(cin.fail())
{
cin.sync();
cin.clear();
cin >> value;
}
test.push_back(value);
}
cout << "-> 输入操作完成.\n";
return;
}
/**
* 子程序名称:ShellSort
* 子程序返回类型:void
* 子程序入口参数:vector<double> &
* 子程序功能:将vector<double>内部从小到大的顺序排序。
**/
void ShellSort(vector<double> & test)
{
int maxsize(static_cast<int>(test.size())); // 求出数组的大小
int gap; // 用于ShellSort时的步进大小
int i; // 用于逐个元素的读取
int j; // 用于逐个已好的数组的元素比较
// 最外层循环,使用gap变量作为循环判断控制变量
// 将gap的初值设为maxsize/2,目的是将第一次的步进量设为总大小的一半
// gap 的初值越大,执行分治的次数就会越多,这时的gap初值大小的设定要视具体情况而定
// 然后,在每一次的循环体执行以后,将gap的值减半
// 在这里设定的gap的大小实际上就是在下面循环中的步进大小,
// 以这些相同的步进大小为准,将数组分割成一个个小数组
for ( gap = maxsize / 2; gap > 0; gap /= 2)
{
// 第二层的循环,使用i变量作为循环判断控制变量
// 将i的初值设为gap,可以想像成当i = gap时,就是新数组中的最后一个数组元素,
// 然后,当步进为gap时,该新数组的下一个元素则在下一个循环中
// 也就是说,该循环是为了控制一个gap步进的末元素的位置,又由于同一个步进的小数组有N个,
// 所以,需要这一个循环来将逐个小数组的位置拿出来
// 在i刚刚进入循环时,假设有数组大小为10,1看作有数,0看作没数,步进为3
// 设它的数组是 0 0 0 1 0 0 0 0 0 0,
// 这样设定以后,在"下一个j"循环当中,会比较的数是 1 0 0 1 0 0 0 0 0 0
// OK,此时从下一个循环"跳回"这循环当中,++i, 0 0 0 0 1 0 0 0 0 0,
// 在"下一个j"循环当中,会比较的数是 0 1 0 0 1 0 0 0 0 0
// 再经过几次循环后,会比较的数会是 0 1 0 0 1 0 0 1 0 0
// 这样一来,就可以看得出,这里是一个经典的插入排序,只是分开了几步为完成而已
// 而循环的结束条件是 i < maxsize, 当i达到maxsize时,则已把一次步进的所有的数进入到新数组中去了
for ( i = gap; i < maxsize; ++i)
{
vector<double>::value_type temp = test[gap];
// 第三层循环,使用j变量作为循环判断控制变量
// 在上一层注释中已说,这里功能是找出每个设定末位置的前面的符合步进条件的元素,
// 如果是要升序排序的话,这里就需要temp < a[j - gap]
// 一步步比较下去,符合条件则执行循环,将新元素移到新数组的新位置
for (j = i; j < maxsize && temp < test[j - gap]; j -= gap)
{
test[j] = test[j - gap];
}
test[j] = temp;
}
}
return;
}
/**
* 子程序名称:ShowArr
* 子程序返回类型:void
* 子程序入口参数:vector<double> &
* 子程序功能:遍历并显示vector<double>&。
**/
void ShowArr(vector <double> & test)
{
cout << "-> 现在开始显示确认刚刚所输入的数组顺序:\n";
cout << "-> ";
vector<double>::const_iterator be(test.begin());
vector<double>::const_iterator en(test.end());
while ( be != en)
{
cout << *be++ << " ";
}
return;
}
(2011.11.29) 05_谢尔排序(Shell's Sort).cpp
最新推荐文章于 2020-04-04 11:41:52 发布