排序算法(一)

前言

常用的排序算法有7种,按照算法的复杂度分为两大类:
1、简单算法:冒泡排序选择排序插入排序
2、优化算法:希尔排序、堆排序、归并排序、快速排序
本文主要讲解和分析这3种简单排序算法。在这之前,还要先介绍一些排序算法的稳定性:假设一个序列中有nums[a]=nums[b],并且a<b,即nums[a]在nums[b]之前,若排序之后nums[a]仍然在nums[b]之前,则说明该排序算法稳定,反之则是不稳定的。

简单排序算法

1.冒泡排序

冒泡排序是一种交换排序,它的基本思想是:两两比较相邻的值,如果反序则进行交换,直到没有反序的记录为止,可以归结为比较、交换。以升序为例,从第一个元素开始,依次比较相邻两个元素的值,如果nums[j]>nums[j+1],则进行交换,这样下来就会选出最大的元素放到最后一个位置上。有n个元素,则需要进行n-1次迭代。
C++代码:

vector<int> BubbleSort(vector<int>& nums)
{
	int len = nums.size();
	for (int i = 1; i < len ; i++)//i表示迭代次数,n个元素需要进行n-1次迭代
	{
		for (int j = 0; j < len -i; j++)//j表示元素位置,第i次迭代的时候只需要进行n-i次比较
		{
			if (nums[j] > nums[j + 1])
			{
				int tmp = nums[j];
				nums[j] = nums[j + 1];
				nums[j + 1] = tmp;
			}
		}
	}
	return nums;
}

复杂度分析:
冒泡排序,不论是一个怎么样的序列,都需要进行n*(n-1)/2次比较,交换次数视原始序列而定,若是一个排好序的数组,则无需交换,若是一个逆序的数组,则需要交换n*(n-1)/2次,复杂度为O(n²)。

稳定性分析
冒泡排序是稳定的排序算法。

2.选择排序

选择排序的思想是:通过n-i次的比较,在n-i+1个元素中找到最小的一个,记为nums[min],将nums[min]与nums[i-1]进行交换,同冒泡排序一样,可以总结为比较、交换。如第一次遍历所有的n个元素,找到最小的元素nums[min],将nums[min]和nums[0]进行交换。
C++代码:

vector<int> SelectSort(vector<int>& nums)
{
	int len = nums.size();
	for (int i = 0; i < len - 1; i++)
	{
		int min = i;
		for (int j = i + 1; j < len; j++)
		{
			if (nums[j] < nums[min])
			{
				int tmp = nums[j];
				nums[j] = nums[min]
				nums[min] = tmp;
			}
		}
	}
	return nums;
}

复杂度分析:
对于一个有n个元素的序列,需要进行n*(n-1)/2次比较,交换次数为0~n-1,最好的情况就是一个排好序的数组,无需进行交换,对坏的情况就是一个逆序的数组,需要进行n-1次交换,复杂度为O(n²)。

稳定性分析
选择排序不是稳定的排序算法。例如6,5,6,4,2,8这个序列,第一次选择交换的时候,会把第一个6和后面的2进行交换,这样第一个6就换到第二个6后面去了,跟原来的先后顺序发生了改变,因此选择排序是不稳定的排序算法。

3.插入排序

插入排序的基本思想是将无序序列插入到有序序列中。基本操作如下:假定nums[0]是已经排序好的序列,则从nums[1]开始,逐个与已排序好的序列进行对比。
C++代码:

vector<int> InsertSort(vector<int>& nums)
{
	int len = nums.size();
	for (int i = 1; i < len; i++)//认为nums[0]是已经排好序的序列
	{
		if (nums[i] < nums[i - 1])//将当前元素与前一个元素比较,若是比前一个小,则依次往前查找至当前元素应在的位置
		{
			int tmp = nums[i];
			int j;
			for (j = i - 1; j >= 0 && tmp < nums[j]; j--)
			{
				nums[j + 1] = nums[j];
			}
			nums[j + 1] = tmp;
		}
	}
	return nums;
}

复杂度分析:
最好的情况是拿到的序列本身就是有序的,需要比较和移动次数均为n;最坏的情况是拿到的序列是倒序的,需要移动和比较的次数是n(n-1)/2。平均时间复杂度为O(n²)。

稳定性分析

插入排序算法是稳定的排序算法,插入过程中序列元素的先后顺序不会被改变。

三种简单排序算法总结

1.冒泡排序、插入排序都是稳定的排序算法,选择排序是不稳定的排序算法。
2.冒泡排序、选择排序、插入排序这三种算法的时间复杂度都是O(n²),但是选择排序法要优于冒泡排序法,因为交换的次数少;插入排序要优于冒泡排序,因为在进行交换的时候,冒泡排序需要进行三次赋值操作,而插入排序只需要进行一次赋值操作:

//冒泡排序
if (nums[j] > nums[j + 1])
{
	int tmp = nums[j];
	nums[j] = nums[j + 1];
	nums[j + 1] = tmp;
}
//插入排序
for (j = i - 1; j >= 0 && tmp < nums[j]; j--)
{
	nums[j + 1] = nums[j];
}

综上所述,在这三种简单排序算法中,性能最好的是插入排序算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值