排序算法的代码--选择排序综合训练题

目录

冒泡和快速的改进???

综合应用题


冒泡和快速的改进???

综合应用题

1、题目:编写双向冒泡算法,在正反两个方向交替进行扫描,即第一趟把关键字最大的元素放在序列的最后面,第二趟把关键字最小的元素放在序列的最前面,如此反复进行。

解析:

这种排序叫做双向起泡。奇数趟时,从前往后比较相邻元素的关键字,遇到逆序即交换,直到把序列中关键字最大的元素移动到序列尾部。偶数趟时,从后往前比较相邻元素的关键字,遇到逆序即交换,直到把序列中关键字最小的元素移动到序列尾部。

#include <stdio.h>
#include <stdbool.h>

typedef int ElemType;
ElemType a[50];//a[]待排序序列

void swap(int *a, int *b)
{
	int temp;
	temp = *a;
	*a = *b;
	*b = temp;
}

void BubbleSort(ElemType a[], int n)
{
	int low = 0, high = n-1,i;
	bool flag = true;
	
	while (low < high && flag)
	{
		
		flag = false;//每一趟开始之前都需要将标志归0.
		
		//奇数趟,正向走,将最大的移动到最后。
		for ( i = low; i < high; i++)
		{
			if (a[i] > a[i+1])
			{
				swap(&a[i],&a[i+1]);
				flag = true;//发生交换
			}	
		}
		high --;

		//偶数趟,倒向走,将最小的移动到最前面。
		for ( i = high; i > low; i--)
		{
			if (a[i] < a[i-1])
			{
				swap(&a[i],&a[i-1]);
				flag = true;
			}
		}
		low ++;
	}	
}

int main()
{
	int n;
	printf("请输入序列个数:\n");
	scanf("%d",&n);
	printf("请输入序列中的元素: \n");
	for (int i = 0; i < n; i++)
	{
		scanf("%d",&a[i]);
	}
	
	BubbleSort(a,n);
	printf("排序好的序列是:\n");
	for (int i = 0; i < n; i++)
	{ 
		printf("%d,",a[i]);
	}
	printf("\n");
	return 0;
}

结果:

请输入序列个数:
10
请输入序列中的元素: 
12 13 39 43 10 33 23 90 82 19
排序好的序列是:
10,12,13,19,23,33,39,43,82,90

自己敲的过程中出现的不足之处:

1、没有想过双向冒泡以后,每趟排序的起始点和结尾点都会变,要添加low和high。还在那啥傻傻的想。。。废物。。。

2、你是憨熊吗?为什么不考虑一下是否要判断越界等情况,只知道写排序过程,就没有想过结束条件是什么吗?

我希望你可以记住!!!判断结束条件!!!

3、那么怎么才是排序结束呢?当然是用flag来标志每一次是否排序,若排序则对flag进行改变。

在定义bool flag = true时,我一开始初始定义成了flag = flase,然后,

因为只有true时while才执行,那么我只能把对flag的判断放在了while循环里面。

因为每趟排序后,flag=true,所以在while循环的开头增加判断:若flag = false则说明没有进行交换对叭?然后跳出循环。

造成了一个后果:是不是傻,是不是傻,一开始你自己规定的就是flag = false呀!!!。所以一遍也不执行,直接跳出。。。

我说怎么排序后没有发生变化。。。害… …

2、已知线性表按顺序存储,且每个元素都是不相同的整形元素,设计把所有奇数移动到所有偶数前边的算法(要求时间最少,辅助空间最少)。

解析:我的看法:没什么新颖的。重点是要求时间最少,辅助空间最少,。那也就是说,循环嵌套层数要少,尽量在原序列上进行移动。                                                                                                王道:本题可基于快速排序的划分思想来设计算法:只需要遍历一次即可。时间复杂度为O(n),空间复杂度O(1),基本思想:先从前向后找到一个偶数元素L(i),再从后向前找到一个奇数元素L(i),将二者交换;重复上述过程,直到low>high。(不完全使用快速排序)。

#include <stdio.h>

typedef int ElemType;
ElemType a[50];

void swap(int *a, int *b)
{
	int temp;
	temp = *a;
	*a = *b;
	*b = temp;
}

void move(ElemType a[],int n)
{
	int low = 0, high = n-1;
	while (low < high)
	{
		while (low < high && a[low] % 2 != 0)
		{
			//只要是奇数就跳过,直到找到一个偶数,跳出while循环。
			low ++;
		}
		while (low < high && a[high] % 2 != 1)
		{
			//只要是偶数就跳过,直到找到一个奇数,跳出while循环。
			high --;
		}
		if (low < high)
		{
			swap(&a[low], &a[high]);//交换。
		}
		low ++; high --;//我居然把这一条件给忘了,不加这一句,i和j的值就一直不变,就会死循环。
	}
}

int main()
{
	int n;
	printf("请输入序列个数:\n");
	scanf("%d",&n);
	printf("请输入序列中的元素: \n");
	for (int i = 0; i < n; i++)
	{
		scanf("%d",&a[i]);
	}
	
	move(a,n);
	printf("排序好的序列是:\n");
	for (int i = 0; i < n; i++)
	{ 
		printf("%d,",a[i]);
	}
	printf("\n");
	return 0;
}

总结一下:1、main函数里好像都差不多,那以后就不写了。2、在考试里遇到要求时间最少、算法最优等等,或者没有暗示又不是超级适合其他排序算法的,那就从快速排序开始试试。

3、试重新编写考点精析中的快速排序的划分算法,使之每次选取的枢轴值都是随机地从当前子表中选择的。

pass吧? 使用随机数来选出pivot.但是,选出的随机数要和第一个元素进行交换,pivot还是=a[low]。

4、试编写一个算法,使之能够在数组L[1…n]中找出第k小的元素(即从小到大排序后处于第k个位置的元素)。

解析:

我的想法是直接对数组进行排序,然后提取L(k),便得到了第k小。但是,这样其平均时间复杂度将达到O(nlog2n)以上。

王道:可以采用小根堆的思想,时间复杂度为O(n+klog2n).

最精彩的还是基于快速排序的划分操作。

主要思想:

5、荷兰国旗问题:设有一个仅有红、白、蓝三种颜色的条块组成的条块序列,请编写一个时间复杂度为 Q ( n ) Q(n) Q(n)的算法,使得这些条块按红、白、蓝的顺序排好,即排成荷兰国旗图案。
6、【2016年统考真题】已知由n(n≥2)个正整数构成的集合 A = {ak ∣ 0 ≤ k < n} ,将其划分为两个不相交的子集A1和 A2,元素个数分别是n1和n2,A1和A2中的元素之和分别为S1和S2。设计一个尽可能高效的划分算法,满足 |n1 − n2|最小且 |S1 − S2|最大。
要求:

1、给出算法的基本设计思想。

2、根据设计思想,采用C语言描述算法,关键之处给出注释。

3、说明你所设计算法的平均时间复杂度和空间复杂度。

猜你喜欢

转载自blog.csdn.net/weixin_48060069/article/details/127156175