主要是理解动图,结合图和代码来分析理解。
- 冒泡排序
平均复杂度:O(n2)
空间复杂度:O(1)
稳定性:稳定
冒泡排序 是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
void Bubblesort(vector<int>& a,int n)
{
for(int i=n-1; i>0; i--)
for(int j=0; j<i; j++)
{
if(a[j]>a[j+1])
swap(a[j],a[j+1]);
}
}
- 选择排序
平均复杂度:O(n2)
空间复杂度:O(1)
稳定性:不稳定
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕
vector<int> selectionSort(vector<int>& a) {
if (a.size() == 0)
return a;
for (int i = 0; i < a.size(); i++) {
int minIndex = i;
for (int j = i; j < a.size(); j++) {
if (a[j] < a[minIndex]) //找到最小的数
minIndex = j;
}
//将最小数与已排序队列末尾元素交换
int temp = a[minIndex];
a[minIndex] = a[i];
a[i] = temp;
}
return a;
}
- 插入排序
平均复杂度:O(n2)
空间复杂度:O(1)
稳定性:稳定
过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间
void Insertsort(vector<int>& a,int n)
{
for(int i=1; i<n; i++)
{
int temp=a[i];
int j=i-1;
while(j>=0&&temp<a[j])
{
a[j+1]=a[j];
j--;
}
a[j+1]=temp;
}
}
- 希尔排序
平均复杂度:O(nlogn)
空间复杂度:O(1)
稳定性:不稳定
希尔排序是简单插入排序经过改进之后的一个更高效的版本,把数组分为多组(每一定间隔(增量)的数为一组),进行多轮插入排序,可以减少移动次数。一开始先选择较大的增量,然后不断缩短增量直至增量为1,变为普通插入排序
void Shellsort(vector<int>& a,int n)
{
for(int gap=n/3; gap>=1; gap=(gap-1)/3+1)//选取增量并不断缩小,直至为1,增量可以任选
{
for(int i=gap; i<n; i++)
{
int temp=a[i];
int j=i-gap;
while(j>=0&&temp<a[j])
{
a[j+gap]=a[j]; //插入排序
j-=gap;
}
a[j+gap]=temp;
}
if(gap<=1)//临界判断
break;
}
}
- 快速排序
平均复杂度:O(nlogn)
空间复杂度:O(n)
稳定性:不稳定
过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序
int Swap(vector<int>&a,int n)
{
int i=0;
for(int j=0; j<=n-2; j++) //循环除基准外的所有元素
if(a[j]<=a[n-1])
swap(a[i++],a[j]);//选取a[n-1]为基准,比其小的放在前面,大的放在后面
//主元可以随机选取,尽量避免最坏情况发生
swap(a[i],a[n-1]);//最后把主元放在中间
return i;
}
void Quicksort(vector<int>& a,int n)
{
if(n<=1)
return;//临界判断
int i=Swap(a,n);//把a的n个元素划分为两部分,取其分界点。
Quicksort(a,i);
Quicksort(a+i+1,n-1-i);//左右两部分递归排序
}
- 归并排序
平均复杂度:O(nlogn)
空间复杂度:O(n)
稳定性:稳定
建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。归并排序是一种稳定的排序方法。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并
void Merge(int* a,int p,int n)
{
int n1=p,n2=n-p;
int* L=new int[n1+1],*R=new int[n2+1];//建立两个数组来分别保存左右两部分的元素
for(int i=0; i<n1; i++) //先将元素复制到数组中
L[i]=a[i];
for(int i=0; i<n2; i++)
R[i]=a[p+i];
L[n1]=R[n2]=INT_MAX; //将末尾元素设为无穷大
//将两组元素合并排排序,相当于设两个指针依次往后比较
for(int i=0,j=0; i+j<n;)
{
if(L[i]<R[j])
{
a[i+j]=L[i];
i++;
}
else
{
a[i+j]=R[j];
j++;
}
}
delete []L;
delete []R;
}
void Mergesort(int* a,int n)
{
if(n<=1)
return;//临界判断
int i=n/2;
Mergesort(a,i);
Mergesort(a+i,n-i);//对左右两部分分别排序(递归)
Merge(a,i,n);//将已排好序的两部分合并
}
- 堆排序
平均复杂度:O(nlogn)
空间复杂度:O(1)
稳定性:不稳定
利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
参考:http://www.west999.com/info/html/chengxusheji/Javajishu/20190217/4612849.html
https://blog.csdn.net/weixin_41190227/article/details/86600821