SelectionSort(单选排序,双选排序)——C语言实现

前言: 

选择排序的思路和我们人脑的思维很相似,是每次都挑选出符合要求的数放到合理的位置。时间复杂度和冒泡排序相同。

(冒泡排序的优点)那么冒泡排序的优点是什么呢?它的优点是进行了一定次数的冒泡以后,数组会得到一个整体相对比较有序的状态。

时间复杂度O(N^2)

空间复杂度O(1)

一.单选择排序

思路:

遍历寻找数列中最大(最小)的元素,与数列最后一个元素交换位置

因为我们要交换数,所以要记录的是下标的位置,而不是数字的值,但同时,必须要保持更新一个max(min),来确认当前的是最值 所对应的下标。

因此代码如下

void Single_SelectionSort(int *a, int length)
{
	int i, j;
	int max_subscript;
	//最后一次剩下一个数不用进行比较,所以i < length - 1
	for (i = 0; i < length - 1; i++)
	{
		int max = -2e9;
		/*
		为什么选择排序中j为什么不是j < length - i - 1 呢,而冒泡是呢?
		因为冒泡会用到a[j+1],有可能越界,所以得-1避免掉。
		*/
		for (j = 0; j < length - i; j++)
		{
			if (a[j] > max)
			{
				max = a[j];
				max_subscript = j;
			}
		}
		swap(&a[max_subscript],&a[length - i - 1]);
	}
}

二.双选排序(对选择排序的效率优化)

这是一次只选一个的单边选择排序,反正不需要开辟额外的数组,空间复杂度是O(1)那么我们为什么不用min和max同时对两边进行排序呢?这样效率会快上一倍,同时复杂度不变!

但是呢,这边里头有个很重要的思维点,想了好久好久。我想可能后面也会遇到。我标记在代码段中了,大家可以先想想。解释我放代码下头,同样代码细节也写在代码注释中:

void Double_SelectionSort(int *a,int length)
{
	int i, j;
	int max_subscript = 0;
	int min_subscript = 0;
	for (i = 0; i < length/2; i++)//循环次数由于每次减少两个,所以只需要长度整除2的次数
	{
		int max = -2e9;
		int min = 2e9;
		for (j = i; j < length - i; j++)// j = i是因为前头的位置被排序好的值占了
		{
			if (a[j] < min)
			{
				min = a[j];
				min_subscript = j;
			}
			if (a[j] > max)
			{
				max = a[j];
				max_subscript = j;
			}
		}
		swap(&a[i], &a[min_subscript]);
		
		if (max_subscript == i)//思维点就在这里
			max_subscript = min_subscript;
		
		swap(&a[length - i - 1],&a[max_subscript]);
	}
}

可以试着删掉那一段,我们会发现数据时对时错。原因是我们的两次交换他是有先后顺序的。如果是同时交换,那不存在问题,可是如果第一次交换以后交换的数据,正是我们下一次交换用的数据,我们下一次交换使用的下标就出现了偏差,但庆幸的是数据不会改变,这正是我们标记下标而不是用辅助数组的好处。所以,我们要多进行一次判断,判断是否有覆盖数据位置,如果有,进行一定处理,没有正常继续。

整体代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define N 30

//之前写过了,就不再全写一遍了
void generate_random_number(int*, int, int);
void swap(int*, int*);


void Single_SelectionSort(int *a, int length)//单选排序
{
	int i, j;
	int max_subscript;
	for (i = 0; i < length - 1; i++)
	{
		int max = -2e9;
		for (j = 0; j < length - i; j++)
		{
			if (a[j] > max)
			{
				max = a[j];
				max_subscript = j;
			}
		}
		swap(&a[max_subscript],&a[length - i - 1]);
	}
}

void Double_SelectionSort(int *a,int length)//双选排序
{
	int i, j;
	int max_subscript = 0;
	int min_subscript = 0;
	for (i = 0; i < length/2; i++)
	{
		int max = -2e9;
		int min = 2e9;
		for (j = i; j < length - i; j++)
		{
			if (a[j] < min)
			{
				min = a[j];
				min_subscript = j;
			}
			if (a[j] > max)
			{
				max = a[j];
				max_subscript = j;
			}
		}
		swap(&a[i], &a[min_subscript]);
		
		if (max_subscript == i)
			max_subscript = min_subscript;
		
		swap(&a[length - i - 1],&a[max_subscript]);
	}
}

int main()
{
	int arr[N + 10] = { 0 };
	generate_random_number(arr, 0, 1024);


	Double_SelectionSort(arr,N);

	printf("排序后数列:\n");
	for (int i = 0; i < N; i++)
		printf("%d ", arr[i]);
	return 0;
}

测试结果如下:

 至此,Single_SelectionSort 与 Double_SelectionSort 完成。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值