实验六 排序相关典型算法实现

2023-12-17 05:01:40

一 实验目的

1.熟悉并掌握各种排序方法的设计思路。

2.掌握各种具体排序算法在计算机上的实现。

3.掌握各种排序方法的性能比较。

二 实验内容及要求

实验内容

1. 编程实现如下功能:

(1)输入同样一组整型数据,作为待排序记录的关键字序列。

(2)在进行直接插入排序的同时,统计在排序方法中对关键字的比较次数和移动次数,并输出统计结果。

(3)在进行冒泡排序的同时,统计在排序方法中对关键字的比较次数和移动次数,并输出统计结果。

(4)在进行简单选择排序的同时,统计在排序方法中对关键字的比较次数和移动次数,并输出统计结果。

2. 编程实现如下功能之一:

(1)希尔排序

(2)快速排序

(3)堆排序

实验要求:

1.键盘输入数据;

2.屏幕输出运行结果。

3.要求记录实验源代码及运行结果。

4.运行环境:CodeBlocks/Dev c++/VC6.0C编译环境

三 实验方法及运行结果

实验一:完成插入排序,冒泡排序,选择排序的操作,并且统计其移动次数和比较次数。

一 算法设计思路

包括五个功能函数:?InputSqlist(Sqlist& l)、InitialSqlist(Sqlist& l)、OutPutSqlist(Sqlist l)、BubbleSort(Sqlist &l)、SelectSort(Sqlist& l)、?InsertSort(Sqlist &l)、和一个主函数

前三个函数分别对应初始化、输入和输出功能。

直接插入排序算法InsertSort(Sqlist &l)的思路:

初始时,将第一个元素视为已排序序列,其余元素为未排序序列。然后,依次将未排序序列中的元素插入到已排序序列的正确位置,直到所有元素都被插入到已排序序列中,完成排序。

首先从第二个元素开始,将其视为当前要插入的元素。接着将当前元素与已排序序列中的元素逐个比较,直到找到插入位置或者已经比较到已排序序列的第一个元素为止。然后在比较的方法中,如果当前元素小于已排序序列中的某个元素,则将该元素后移一位,为当前元素腾出插入位置。将当前元素插入到正确的位置,即将其放置在比它大的元素之前。最后重复上面两步,直到所有元素都被插入到已排序序列中。

冒泡排序算法BubbleSort(Sqlist &l)的思路:

基本思想是通过不断比较相邻元素的大小,将较大的元素逐步交换到右侧,从而实现排序的目的。从序列的第一个元素开始,依次比较相邻的两个元素。如果前一个元素大于后一个元素,则交换它们的位置,将较大的元素往右移动。继续比较下一对相邻元素,重复上一步,直到比较到序列的倒数第二个元素。重复执行执行上述步骤,直到没有需要交换的元素,即序列已经完全排序。

选择排序算法SelectSort(Sqlist& l)的思路:

选择排序是每次从待排序的序列中选择最小(或最大)的元素,放到已排序序列的末尾(或开头),从而逐步形成有序序列。

首先遍历待排序序列,将第一个元素视为当前最小(或最大)元素。然后从剩余未排序的元素中,依次找到最小(或最大)的元素,并记录其位置。接着将找到的最小(或最大)元素与当前最小(或最大)元素进行交换,将最小(或最大)元素放到已排序序列的末尾(或开头)。最后重复上面两步,直到所有元素都被放置到正确的位置上。

选择排序算法不断地选择最小(或最大)元素,并将其放置到已排序序列的末尾(或开头)。这样,每一次选择排序都会确定一个元素的最终位置,直到所有元素都被放置到正确的位置上,完成排序。选择排序每次只需要进行一次交换操作。

二 源程序代码
/*1. 编程实现如下功能:
(1)输入同样一组整型数据,作为待排序记录的关键字序列。
(2)在进行直接插入排序的同时,统计在排序过程中对关键字的比较次数和移动次数,并输出统计结果。
(3)在进行冒泡排序的同时,统计在排序过程中对关键字的比较次数和移动次数,并输出统计结果。
(4)在进行简单选择排序的同时,统计在排序过程中对关键字的比较次数和移动次数,并输出统计结果。
*/
#define MAXSIZE 1000
typedef struct Sqlist
{
	int Arr[MAXSIZE];
	int Length;
	int Comparison;
	int Move;
};
void InsertSort(Sqlist &l)
{
	int j=0;
	//直接排序只有第一个元素有序
	for ( int i = 2; i <= l.Length; i++)//从2开始排序
	{
		l.Comparison+=2;
		if (l.Arr[i] < l.Arr[i - 1])
		{
			l.Arr[0] = l.Arr[i];
			l.Arr[i] = l.Arr[i - 1];
			l.Move += 4;
			for (j = i - 2; l.Arr[0] < l.Arr[j];--j)
			{
				l.Comparison+=2;
				l.Arr[j + 1] = l.Arr[j];
				l.Move+=2;
			}
			l.Comparison+=2;//判断跳出循环还有一次
			l.Arr[j + 1] = l.Arr[0];
		}
			l.Move+=2;
		
	}
}

void InputSqlist(Sqlist& l)
{
	cout << "请输入要输入的数组的长度" << endl;
	cin >> l.Length;
	cout << "请输入数组的数据" << endl;

	for (int i = 1; i <= l.Length; i++)
		cin >> l.Arr[i];//此处arr[0]作为哨兵单元不放置元素
}
void InitialSqlist(Sqlist& l)
{
	for (int i = 0; i < MAXSIZE; i++)
		l.Arr[i] = 0;
	l.Length = 0;
	l.Move = 0;
	l.Comparison = 0;
}


void OutPutSqlist(Sqlist l)
{
	for (int i = 1; i <= l.Length; i++)
		cout << l.Arr[i] << " ";

	cout << "\n此次的比较次数为" << l.Comparison << endl;
	cout << "此次的移动次数" << l.Move << endl;
}
void BubbleSort(Sqlist &l)
{
	int max = 0, min = 0; int tem;
	for (int j = 1; j <=l.Length-1; j++)        //此处循环length-1次 就是数组长度-1次内部操作
	{
		for (int i = 2; i <=l.Length-j+1; i++)    //一次内部循环可以将一个数“送”到正确位置
		{                                //比如第一次内部循环结束后可以让arr[9]变成最大值9
			max = l.Arr[i - 1];
			min = l.Arr[i];
			l.Comparison++;
			if (min <= max)
			{
				tem = max;
				max = min;
				min = tem;
			}
			l.Arr[i - 1] = max;
			l.Arr[i] = min;
			l.Move+=3;
		}
	}
}
void SelectSort(Sqlist& l)
{
	for (int i = 1; i < l.Length; i++)
	{
		int flag = i;
		int tem; int min = l.Arr[i];
		for (int j = i+1; j <=l.Length; j++)
		{
			l.Comparison++;
			if (min > l.Arr[j])
			{
				min = l.Arr[j];
				flag = j;
			}
		}
			tem = l.Arr[i];
			l.Arr[i] = min;
			l.Arr[flag] = tem;
			l.Move += 3;
	}
}
int main()
{
	Sqlist l; int n = 0;


	InitialSqlist(l);
	InputSqlist(l);
	cout << "\n插入排序:" << endl;
	InsertSort(l);
	OutPutSqlist(l);

	InitialSqlist(l);
	InputSqlist(l);
	cout << "\n冒泡排序:" << endl;
	BubbleSort(l);
	OutPutSqlist(l);


	InitialSqlist(l);
	InputSqlist(l);
	cout << "\n选择排序:" << endl;
	SelectSort(l);
	OutPutSqlist(l);

	return 0;
}

实验二:完成快速排序、堆排序、希尔排序中任意一个(待更新)。

一 算法设计思路

快速排序QuickSort (Sqlist&l, int left, int right)算法思路:

具体的步骤如下:选择一个基准元素(选择第一个)。将序列中的元素分为两部分,小于等于基准元素的放在左边,大于基准元素的放在右边。这个方法称为分区。对左右两个子序列分别进行快速排序,递归地重复上述步骤,直到子序列的长度为1或0,此时子序列已经有序。合并左子序列、基准元素和右子序列,得到最终的有序序列。

二 源程序代码

typedef struct Sqlist
{
	int Arr[MAXSIZE];
	int Length;
	int Comparison;
	int Move;
};
void InputSqlist(Sqlist& l)
{
	cout << "请输入要输入的数组的长度" << endl;
	cin >> l.Length;
	cout << "请输入数组的数据" << endl;

	for (int i = 1; i <= l.Length; i++)
		cin >> l.Arr[i];//此处arr[0]作为哨兵单元不放置元素
}
void InitialSqlist(Sqlist& l)
{
	for (int i = 0; i < MAXSIZE; i++)
		l.Arr[i] = 0;
	l.Length = 0;
	l.Move = 0;
	l.Comparison = 0;
}
void OutPutSqlist(Sqlist l)
{
	for (int i = 1; i <= l.Length; i++)
		cout << l.Arr[i] << " ";

	/*cout << "\n此次的比较次数为" << l.Comparison << endl;
	cout << "此次的移动次数" << l.Move << endl;*/
}

void QuickSort(Sqlist&l, int left, int right)
{
    int i = left - 1, j = right + 1, x = l.Arr[left + right >> 1]; //l代表数组起始端 r代表数组结束
    if (left >= right) return;//递归结束条件
    while (i < j)
    {
        do i++; while (l.Arr[i] < x);  //确保l.Arr[i]全是小于x的
        do j--; while (l.Arr[j] > x);  //确保l.Arr[j]全是大于x的
        if (i < j) swap(l.Arr[i], l.Arr[j]); //当停下时 i和j 都不满足 所以交换
    }
    QuickSort(l, left, j); QuickSort(l, j + 1, right);
    // 也可以是 QuickSort(l.Arr,l,i-1);QuickSort(l.Arr,i,r);
// i本身在左边最后一次执行的时候 到区间中点右边 所以更偏左边的是i-1 ,递归区间实现全覆盖但不交叉所以右边是i,r 左边是 l,i-1
// j和j+1同理
}
int main()
{
	Sqlist l;
	InitialSqlist(l);
	InputSqlist(l);
	QuickSort(l, 1, l.Length);
	OutPutSqlist(l);
}

四 调试情况、设计技巧及体会

目录

一 实验目的

二 实验内容及要求

实验内容:

1. 编程实现如下功能:

2. 编程实现如下功能之一:

实验要求:

三 实验方法及运行结果

实验一:完成插入排序,冒泡排序,选择排序的操作,并且统计其移动次数和比较次数。

一 算法设计思路

二 源程序代码

实验二:完成快速排序、堆排序、希尔排序中任意一个(待更新)。

一 算法设计思路

二 源程序代码

四 调试情况、设计技巧及体会


在实现本次实验的相关排序算法的实现方法中,以下是我犯的错误以及相应的修改方法以及收获:

1.错误:未正确处理边界条件。

修改方法:在实现插入排序算法时,要确保对数组的索引进行正确的边界检查。例如,循环变量的范围应该是从1到n(数组长度),而不是从0到n-1。此外,还要确保在插入元素时,正确处理数组的边界情况,以避免越界错误。

收获:在编写代码时,始终要注意数组索引的边界情况,并进行适当的边界检查。确保循环变量的范围和条件正确设置,以避免数组越界错误。

2.错误:未正确处理重复元素的情况。

修改方法:在实现插入排序算法时,要考虑重复元素的情况。如果存在重复元素,确保它们被正确地插入到已排序的子数组中,并保持它们的相对顺序。可以通过在插入位置之前或之后进行适当的调整来处理重复元素。

收获:处理重复元素时,要仔细考虑它们的相对顺序,并确保它们被正确地插入到已排序的子数组中。可以使用适当的比较条件和调整方法来处理重复元素,以获得正确的排序结果。

3.错误:未正确统计移动和比较次数。

修改方法:在统计移动和比较次数时,要确保在实际发生移动和比较操作后进行统计。例如,在元素交换或插入位置时,增加相应的计数器。同时,要注意统计的粒度,可以在排序算法的最后输出统计结果,或者在每一次移动或比较操作后即时输出统计结果。

收获:在编写代码时,要注意在正确的位置统计移动和比较次数。确保在实际发生移动和比较操作后进行计数,以获得准确的统计结果。同时,要灵活选择统计的粒度,以适应不同的需求。

4.错误:未正确处理数组为空或只有一个元素的情况。

修改方法:在实现选择排序算法时,要考虑特殊情况,如数组为空或只有一个元素的情况。在这种情况下,数组已经是有序的,无需进行排序操作。可以通过添加条件判断来处理这种情况,直接返回或跳过排序操作。

收获:在编写代码时,要考虑特殊情况,并进行相应的处理。特别是在排序算法中,要注意处理数组为空或只有一个元素的情况,以避免不必要的操作和错误。

在这次实验中我收获了很多,这将未我将来学好算法打下良好的基础,同时我觉得自己还应该继续加深对这些算法的理解,并进行相关的改写来实现一些功能,让他们得到应用。

?

文章来源:https://blog.csdn.net/qq_73625278/article/details/135039637
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。