选择排序和交换排序

前言

在上篇博客中已经介绍了插入排序中的直接插入排序希尔排序,这篇博客将会介绍选择排序交换排序
##

选择排序

选择排序的基本思想:
每一次从待排序的数据元素中选出最小(或最大)的⼀个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

直接选择排序

思路:

  1. 在元素集合array[i]--array[n-1] 中选择关键码最大(小)的数据元素
  2. 若它不是这组元素中的最后⼀个(第⼀个)元素,则将它与这组元素中的最后⼀个(第⼀个)元素交换
  3. 在剩余的array[i]--array[n-2](array[i+1]--array[n-1]) 集合中,重复上述步骤,直到集合剩余1个元素

在这里插入图片描述

代码实现:

void SelectSort(int* arr, int n)
{
	int begin = 0;
	while (begin < n-1)
	{
		int mini = begin;
		for (int i = begin+1; i < n; i++)
		{
			if (arr[mini] > arr[i])
			{
				mini = i;
			}
		}
		swap(&arr[begin], &arr[mini]);
		begin++;
	}
}

在这里插入图片描述
优化:
我们可以同时将最大和最小值分别放入数组的头和尾

void SelectSort(int* arr, int n)
{
	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		int mini = begin;
		int maxi = end;
		for (int i = begin + 1; i <=end-1; i++)
		{
			if (arr[mini] > arr[i])
			{
				mini = i;
			}
			if (arr[maxi] < arr[i])
			{
				maxi = i;
			}
		}
		if (maxi == begin)
		{
			maxi = mini;
		}
		swap(&arr[begin], &arr[mini]);
		swap(&arr[end], &arr[maxi]);
		begin++;
		end--;
	}
}

在这里插入图片描述
直接选择排序的特性总结:

  • 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
  • 时间复杂度:O(N^2)
  • 空间复杂度:O(1)

堆排序

堆排序是指利用堆积树(堆)这种数据结构所设计的⼀种排序算法,它是选择排序的⼀种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。
在⼆叉树章节我们已经实现过堆排序,这里不再赘述。

交换排序

交换排序基本思想:所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置
交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动

冒泡排序

冒泡排序是⼀种最基础的交换排序,之所以叫做冒泡排序,因为每⼀个元素都可以像小气泡⼀样,根据自身大小⼀点⼀点向数组的⼀侧移动。
在这里插入图片描述

void BubbleSort(int* a, int n)
{
	int exchange = 0;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n - i - 1; j++)
		{
			if (a[j] > a[j + 1])
			{
				exchange = 1;
				swap(&a[j], &a[j + 1]);
			}
		}
		if (exchange == 0)
		{
			break;
		}
	}
}

在这里插入图片描述
冒泡排序的特性总结:

  • 时间复杂度:O(N^2)
  • 空间复杂度:O(1)

快速排序

快速排序是Hoare于1962年提出的⼀种⼆叉树结构的交换排序方法,其基本思想为:
任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

hoare版本

思路:

  1. 创建左右指针,确定基准值
  2. 从右向左找出比基准值小的数据,从左向右找出比基准值大的数据,左右指针数据交换,进入下次循环
int _QuickSort(int* arr, int left, int right)
{
	int keyi = left;
	left++;
	while (left <= right)
	{
		while (left <= right && arr[left] < arr[keyi])
		{
			left++;
		}
		while (left <= right && arr[right] > arr[keyi])
		{
			right--;
		}
		if (left <= right)
		{
			swap(&arr[left++], &arr[right--]);
		}
	}
	swap(&arr[keyi],&arr[right]);
	return right;
}

void QuickSort(int* arr, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	int keyi = _QuickSort(arr, left, right);
	QuickSort(arr, left, keyi - 1);
	QuickSort(arr, keyi + 1, right);
}

在这里插入图片描述

问题1:为什么跳出循环后right位置的值⼀定不大于keyi
left > right 时,即right走到left的左侧,而left扫描过的数据均不大于keyi,因此right此时指向的数据⼀定不大于keyi

问题2:为什么leftright指定的数据和keyi值相等时也要交换?
相等的值参与交换确实有⼀些额外消耗。实际还有各种复杂的场景,假设数组中的数据大量重复时,无法进行有效的分割排序。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值