排序算法
这里主要介绍3种排序算法,其余几种排序算法后续会更新。
冒泡排序法
冒泡排序法是最简单的一种排序算法,核心思想是每遍历一次数组,就通过相邻元素比较交换的方式将未排序区[0,n-i-1)的最大值(这里默认是升序排序)放到未排序区的最后位置,未排序区的大小减一(i增加1,就表示未排序区大小减一)。
代码如下:
void bubbleSort(vector<int>& nums)
{
int n=nums.size();
//遍历n-1次数组
for(int i=0;i<n-1;i++)
{
//每次遍历,比较相邻元素交换,将最大值冒泡到未排序区的尾部,下次遍历未排序区大小减一
for(int j=0;j<n-i-1;j++)
{
if(nums[j]>nums[j+1])
{
swap(nums[j],nums[j+1]);
}
}
}
};
算法平均时间复杂度:O(N^2),空间复杂度:O(1)。
算法稳定性:稳定。
最好时间复杂度:数组完全有序时,不需要在内部循环进行任何的交换操作,时间复杂度为O(N);
最差时间复杂度:数组完全逆序时,需要在内部循环进行n(n-1)/2次交换,时间复杂度是O(N^2)。
选择排序法
选择排序法的核心思想是遍历数组时,把未排序区[i,n)中的最小值放到下标i的位置。
注意我们给出了两个代码版本,版本一中nums[i]和nums[j]比较,版本二中nums[j]和nums[j-1]比较,与冒泡放置元素方式一样。建议选择版本一。
代码如下:
//代码版本一:
void selectSort(vector<int>& nums)
{
int n=nums.size();
//遍历n次数组
for(int i=0;i<n;i++)
{
//未排序区[i,n)的最小值放到下标i处。
for(int j=i;j<n;j++)
{
if(nums[i]>nums[j])
{
swap(nums[i],nums[j]);
}
}
}
}
//版本二:
void selectSort(vector<int>& nums)
{
int n=nums.size();
for(int i=0;i<n;i++)
{
for(int j=n-1;j>i;j--)
{
if(nums[j-1]>nums[j])
{
swap(nums[j-1],nums[j]);
}
}
}
}
算法时间复杂度:O(N^2),空间复杂度:O(1).
算法稳定性:不稳定
最好时间复杂度:数组即使有序,也需要在未排序区进行比较和移动操作选出最小值,时间复杂度为O(N^2);
最差时间复杂度:数组完全逆序时,时间复杂度是O(N^2)。
插入排序法
插入排序法的核心思想是遍历数组元素nums[i]时,每处理一个新的元素时,那么就将这个元素插入到排序区[0,i]中。版本一中注意第二轮循环采用逆序遍历的方式。建议选择版本一,因为一中有break,对于数组中只有少量乱序的情况非常友好。
代码如下:
void insertSort(vector<int>& nums)
{
int n=nums.size();
for(int i=0;i<n;i++)
{
for(int j=i;j>0;j--)
{
if(nums[j]<nums[j-1])
{
swap(nums[j],nums[j-1]);
}
else break;
}
}
}
void insertSort(vector<int>& nums)
{
int n=nums.size();
for(int i=0;i<n;i++)
{
for(int j=0;j<=i;j++)
{
if(nums[i]<nums[j])
{
swap(nums[i],nums[j]);
}
}
}
}
算法时间复杂度:O(N^2),空间复杂度:O(1).
算法稳定性:稳定
最好时间复杂度:数组完全有序时,不需要在内部循环进行任何的比较和移动操作,时间复杂度为O(N);
最差时间复杂度:数组完全逆序时,时间复杂度是O(N^2)。