(2011.11.29) 05_谢尔排序(Shell's Sort).cpp

 
// 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;
}

你可能感兴趣的:(shell,vector,测试,iterator,扩展)