C++——使用简单数组实现排序算法,并进行比较

题目:

使用简单数组实现下面各种排序算法,并进行比较。
排序算法:
1、插入排序
2、希尔排序
3、冒泡排序
4、快速排序
5、简单选择排序
6、堆排序(选作)
7、归并排序(选作)
8、基数排序(选作)
9、其他
要求:
1、测试数据分成三类:正序、逆序、随机数据
2、对于这三类数据,比较上述排序算法中关键字的比较次数和移动次数(其中关键字交换计为3次移动)。
3、对于这三类数据,比较上述排序算法中不同算法的执行时间,精确到微秒(选作)
4、对2和3的结果进行分析,验证上述各种算法的时间复杂度
编写测试main()函数测试线性表的正确性。

需求分析:

(1)输入的形式:整形数组,且需要把整形数组的第一个元素空出来。
(2)输出的形式:也为整形数组,且是被从小到大排序过后的整形数组,并输出每种排
序成功前所需用到的比较次数、移动次数。
(3)程序所能达到的功能:将用户输入的数组进行排序,并输出每种排序方式所需要的
比较次数和移动次数。
(4)测试数据:正确输入: 7 6 5 4 3 2 1
正确输出:1 2 3 4 5 6 7
直接插入排序比较次数:27
直接插入排序移动次数:33
1 2 3 4 5 6 7
希尔排序比较次数:17
希尔排序移动次数:19
1 2 3 4 5 6 7
冒泡排序的比较次数:21
冒泡排序的移动次数:63
1 2 3 4 5 6 7
快速排序的比较次数:21
快速排序的移动次数:18
1 2 3 4 5 6 7
简单排序的比较次数:21
简单排序的移动次数:9

详细设计:

Main:定义数组,输入数据,调用函数;
InsertSort: 对main函数中传过来的数组进行直接插入排序:
(1)用n-1趟循环将数组r[]中较大的数存在r[0]中,移动次数加一;
(2)用另一个内层循环将r[]中的数与r[0]比较,并在查找的过程中边查找边
后移;移动次数和比较次数均加一。
(3)在较外层的比较后增加比较次数。
(4)用一次循环从1到n将排序后的r输出。
(5)输出直接插入排序的比较次数和移动次数。
ShellInsert:对main函数中传过来的数组进行希尔排序:
(1)以d为增量将原数组分组;
(2)在d+1到n之间进行一趟希尔排序:
(2.1) 在每次“一趟希尔排序”中,将每组的较大数存在r[0]中,移动次数加一,比较次数加一;
(2.2) 用循环从后往前将数组中的数与r[0]比较,并把较大的数向后移,以d为增量变换。移动次数加一,比较次数加一。
(2.3) 最后将r[0]存在最后的循环停止位置,移动次数加一。
(3)用一次循环从1到n将排序后的r[]输出。
(4)输出希尔排序的比较次数和移动次数。
BubbleSort:对main函数中传过来的数组进行冒泡排序:
(1)用n设置初始化时无序元素的范围。
(2)用for循环在每趟排序的无序元素范围内进行相邻元素的比较;若前一
个元素大于后一个元素,则将两个数进行交换,并重置无序元素的范
围,使下一次排序的无序元素范围减小。移动次数加3,比较次数加
一。
(3)在无序元素范围不为0的时候,再次进行第二步。
(4)用一次循环从1到n将排序后的r[]输出。
(5)输出冒泡排序的比较次数和移动次数。
QSort:对main函数中传过来的数组进行快速排序:
(1)用i和j设置快速排序的左右分区;
(2)在左右分区依然存在的情况下,调用Partion进行一次快排,并得到一次快排后的新的分区分界值。
(3)通过递归的方式再次在新的分区中进行快速排序。
Partion:对QSort函数中传过来的数组在其所指定的分区中进行快速排序一趟排序:
(1)通过Partion的传递参数中确定一趟排序所需的分区的左界和右界,并保存
第一个元素作为基准元素。
(2)在分区内依然有元素的情况下,先从右侧扫描,寻找小于基准元素的数并将其前移,比较次数加一。
(3)将基准元素存在右侧扫描结束的地方,移动次数加一。
(4)再左侧扫描,寻找大于或等于基准元素的数并将其后移,比较次数加一。
(5)一次排序基本结束,将轴值移动至i=j的位置,移动次数加一,并返回分区的分界值。
cQ
(1)调用QSort;
(2)用一次循环从1到n将排序后的r[]输出。
(3)输出快速排序的比较次数和移动次数。
Selectsort:对main函数中传过来的数组进行排序:
(1)在n-1趟循环中,用index记录查找的最小位置。
(2)在内层循环中,若某个位置的数值小于index位置处的数值,则将此位置记录为新的index,并使比较次数加一。
(3)若第一个就是最小元素,则不用交换;若第一个不是最小元素,则利用r[0]作为临时空间交换记录,将查找到的该位置的数值与index处的数值交换。移动次数加三。
(4)用一次循环从1到n将排序后的r[]输出。
(5)输出简单排序的比较次数和移动次数。

调试分析:

这次实验的主要难点是比较和移动的次数的计数。但是只要对代码有一定的了解和掌握,就可以成功。

用户使用说明:

输入的必须是整形数,若需要改变所需排序数组的元素个数,则需要改变main函数代码对应位置。

测试结果:

输入:5 2 4 6 3 1 7
输出:1 2 3 4 5 6 7
直接插入排序比较次数:16
直接插入排序移动次数:18
1 2 3 4 5 6 7
希尔排序比较次数:18
希尔排序移动次数:18
1 2 3 4 5 6 7
冒泡排序的比较次数:16
冒泡排序的移动次数:30
1 2 3 4 5 6 7
快速排序的比较次数:13
快速排序的移动次数:17
1 2 3 4 5 6 7
简单排序的比较次数:21
简单排序的移动次数:12

主程序:

/* 
使用简单数组实现下面各种排序算法,并进行比较。
排序算法:
   		1、插入排序
   		2、希尔排序
3、冒泡排序
4、快速排序
5、简单选择排序
6、堆排序(选作)
7、归并排序(选作)
8、基数排序(选作)
9、其他

2018.06.06 created by Cheng Zixin

*/
#include<iostream>
using namespace std;
static int com = 0, mov = 0;
void InsertSort(int r[], int n)
{
	int m=0,compare1=0,move1=0;
	for (int i = 2; i <= n; i++)     //i从2~n循环,共n-1趟排序
	{
		if (r[i] < r[i - 1])
		{
			r[0] = r[i]; move1++;
			for (int j = i - 1; r[0] < r[j]; j--)  //边查找边后移
			{
				r[j + 1] = r[j]; m = j;
				/*for (int p = 1; p <= n; p++)
					cout << r[p] << " ";
				cout << "又一次" << endl;*/
				move1++,compare1++;
			}
			r[m] = r[0]; move1++;
		}
		compare1++;
	}
	for (int i = 1; i <= n; i++)
		cout << r[i]<<" ";
	cout << endl;
	cout << "直接插入排序比较次数:" << compare1 << endl;
	cout << "直接插入排序移动次数:" << move1 << endl;
}
//希尔排序
void ShellInsert(int r[], int n)
{
	int compare2 = 0,move2=0;
	for (int d = n / 2; d >= 1; d = d / 2)   //以d为增量
	{
		for (int i = d + 1; i <= n; i++)   //一趟希尔排序
		{
			if (r[i] < r[i - d])
			{
				int m;
				r[0] = r[i]; move2++;
				for (int j = i - d; j > 0 && r[0] < r[j]; j = j - d)
				{
					r[j + d] = r[j];  m = j;
					compare2++; move2++;
				}
				r[m] = r[0]; move2++;
			}
			compare2++;
		}
	}
	for (int i = 1; i <= n; i++)
		cout << r[i] << " ";
	cout << endl;
	cout << "希尔排序比较次数:" << compare2 << endl;
	cout << "希尔排序移动次数:" << move2 << endl;
}
//冒泡排序(改进)
void BubbleSort(int r[], int n)
{
	int compare3 = 0, move3 = 0;
	int pos = n;  //初始化时无序元素的范围
	while (pos != 0)
	{
		int bound = pos;   //本趟排序无序元素的范围
		pos = 0;
		for (int i = 1; i < bound; i++)
		{
			if (r[i] > r[i + 1])  //相邻元素比较
			{
				r[0] = r[i]; r[i] = r[i + 1]; r[i + 1] = r[0];//交换
				pos = i; move3 = move3 + 3; 
			}
			compare3++;
		}
	}
	for(int i=1;i<=n;i++)
	    cout << r[i] << " ";
	cout << endl;
	cout << "冒泡排序的比较次数:" << compare3 << endl;
	cout << "冒泡排序的移动次数:" << move3 << endl;
}
//快速排序
int Partion(int r[], int first, int end)  //快速排序一趟排序
{
	int i = first;  //分区的左界
	int j = end;  //分区的右界
	int pivot = r[i];  //保存第一个元素,作为基准元素
	while (i < j)
	{
		while ((i < j) && (r[j] >= pivot))  //右侧扫描,寻找<pivot的元素前移
			j--,com=com+1;
		r[i] = r[j]; mov++;
		while ((i < j) && (r[i] <= pivot))  //左侧扫描,寻找>=pivot的元素后移
			i++,com=com+1;
		r[j] = r[i]; mov++;
	}
	r[i] = pivot; mov++; //将轴值移动至i=j的位置
	return i;  //返回分区的分界值i
}
void Qsort(int r[], int i, int j)
{
	if (i < j)
	{
		int pivotloc = Partion(r, i, j);
		Qsort(r, i, pivotloc - 1);  //左分区快速排序
		Qsort(r, pivotloc + 1, j);  //右分区快速排序
	}
}
void cQ(int r[], int n)
{
	Qsort(r, 1, n); 
	for (int m = 1; m <= n; m++)
		cout << r[m] << " ";
	cout << endl;
	cout << "快速排序的比较次数:"<<com<<endl;
	cout << "快速排序的移动次数:"<<mov<<endl;
}
//完整简单选择排序
void Selectsort(int r[], int n)
{
	int compare4 = 0, move4 = 0;
	for (int i = 1; i < n; i++)  //n-1趟排序
	{
		int index = i;   //查找最小位置的记录index
		for (int j = i + 1; j <= n; j++)
		{
			if (r[j] < r[index])
				index = j; 
			compare4++;
		}
		if (index != i)   //若第一个就是最小元素,则不用交换
		{
			r[0] = r[i];
			r[i] = r[index];
			r[index] = r[0];  //利用r[0]作为临时空间交换记录
			move4 = move4 + 3;
		}
	}
	for (int i =1 ; i <=n; i++)
		cout << r[i] << " ";
	cout << endl;
	cout << "简单排序的比较次数:" <<compare4<< endl;
	cout << "简单排序的移动次数:" <<move4<< endl;
}
int main()
{
	int r[8];
	r[0] = 0;
	for (int i = 1; i < 8; i++)
		cin >> r[i];
	int a[8] = { 0 }, b[8] = { 0 }, c[8] = { 0 }, d[8] = { 0 };
	for (int i = 0; i < 8; i++)
	{
		a[i] = b[i] = c[i] = d[i] = r[i];
	}
	//int r[8] = { 0,7,6,5,4,3,2,1};
	//int r[8] = {0,12,15,9,20,10,31,24};
	InsertSort(r, 7);
	ShellInsert(a,7);
	BubbleSort(b, 7);
	cQ(c, 7);
	Selectsort(d, 7);
	system("pause");
	return 0;
}

如果对您有帮助,请点赞+评论~

  • 6
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值