一,冒泡排序
时间复杂度:O(n²) 稳定性:稳定
步骤
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
动画演示
代码实现
#include <iostream>
using namespace std;
int main()
{
int a[5]={10,45,66,89,3};
for(int i=0;i<4;i++)
{
for(int j=0;j<4-i;j++)
{
if(a[j]>a[j+1])
swap(a[j],a[j+1]);
}
}
for(int i=0;i<5;i++)
cout<<a[i]<<" ";
return 0;
}
二,选择排序
时间复杂度:O(n²) 稳定性:不稳定
步骤
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
重复第二步,直到所有元素均排序完毕。
动画演示
代码实现
#include <iostream>
using namespace std;
int main()
{
int a[5]={10,45,66,89,3};
for(int i=0;i<5;i++)
{
int minn=i;
for(int j=i;j<5;j++)
{
if(a[j]<a[minn])
minn=j;
}
swap(a[i],a[minn]);
}
for(int i=0;i<5;i++)
cout<<a[i]<<" ";
return 0;
}
三,快速排序
时间复杂度:O(nlogn) 稳定性:不稳定
原理
快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。
步骤
首先确定一个分界点x,随便在数组中找一个值作为分界点,可以是左边界,右边界,中间值或者随机
然后调整区间,把区间一分为二,左半边的数都小于等于x,右半边的数都大于等于x
最后递归处理左右两段
动画演示
代码实现
#include <iostream>
#include <algorithm>
using namespace std;
void quicksort(int s[],int l,int r)
{
if(l>=r) return;
int mid=s[l+r>>1],i=l-1,j=r+1;
while(i<j)
{
while(s[++i]<mid);
while(s[--j]>mid);
if(i<j) swap(s[i],s[j]);
}
quicksort(s,l,j);
quicksort(s,j+1,r);
}
int main()
{
int a[10]={4,3,12,45,66,67,99,1,76,32};
quicksort(a,0,9);
for(int i=0;i<10;i++)
cout<<a[i]<<" ";
return 0;
}
四、归并排序
时间复杂度:nlogn 稳定性:稳定
原理
归并排序和快速排序基本是类似的,才是用的分治的思想,作为一种典型的分而治之的算法应用,归并排序的实现一般有两种方法
自上而下的迭代
自下而上的迭代
步骤
确定分界点,可以直接把中间点当分界点
递归排序左边和右边
归并,把两个有序的数组合并成一个有序的数组
动画演示
代码实现
#include <iostream>
#include <algorithm>
using namespace std;
int a[10]={4,3,12,45,66,67,99,1,76,32},temp[15];
void mergesort(int s[],int l,int r)
{
if(l>=r) return;
int mid=l+r>>1;
mergesort(s,l,mid),mergesort(s,mid+1,r);
int k=0,i=l,j=mid+1;
while(i<=mid&&j<=r)
{
if(s[i]<s[j])
temp[k++]=s[i++];
else
temp[k++]=s[j++];
}
while(i<=mid)
{
temp[k++]=s[i++];
}
while(j<=r)
{
temp[k++]=s[j++];
}
for(int a=l,b=0;a<=r;a++,b++)
s[a]=temp[b];
}
int main()
{
mergesort(a,0,9);
for(int i=0;i<10;i++)
cout<<a[i]<<" ";
return 0;
}
五,插入排序
时间复杂度:O(n²) 稳定性:稳定
原理
插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
步骤
将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
动画演示
代码实现
#include <iostream>
#include <algorithm>
using namespace std;
void insertionsort(int a[])
{
for(int i=0;i<10;i++)
{
int temp=a[i];
int j=i;
while(a[j-1]>temp&&j>0)
{
a[j]=a[j-1];
j--;
}
a[j]=temp;
}
}
int main()
{
int a[10]={4,3,12,45,66,67,99,1,76,32};
insertionsort(a);
for(int i=0;i<10;i++)
cout<<a[i]<<" ";
return 0;
}
六、希尔排序
时间复杂度:O(n²) 稳定性:不稳定
原理
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
- 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
- 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;
希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。
步骤
选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;
按增量序列个数 k,对序列进行 k 趟排序;
每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
动画演示
代码实现
#include <iostream>
#include <algorithm>
using namespace std;
int a[10]={4,3,12,45,66,67,99,1,76,32};
void shellsort(int s[])
{
int j;
int temp;
for(int k=5;k>0;k=k/2)
{
for(int i=k;i<10;i++)
{
temp=s[i];
for(j=i-k;j>=0&&a[j]>temp;j-=k)
a[j+k]=a[j];
a[j+k]=temp;
}
}
}
int main()
{
shellsort(a);
for(int i=0;i<10;i++)
cout<<a[i]<<" ";
return 0;
}
七、堆排序
时间复杂度:O(nlogn) 稳定性:不稳定
原理
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:
- 大根堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
- 小根堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;
步骤
创建一个堆 H[0……n-1];
把堆首(最大值)和堆尾互换;
把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置;
重复步骤 2,直到堆的尺寸为 1。
动画演示
代码实现
#include <iostream>
#include <algorithm>
using namespace std;
int h[11]={0,2,4,6,1,7,88,12,31,14,55};
int sizee=10;
void down(int u)
{
int t=u;
if(u*2<=sizee&&h[u*2]<h[t]) t=u*2;
if(u*2+1<=sizee&&h[u*2+1]<h[t]) t=u*2+1;
if(u!=t)
{
swap(h[u],h[t]);
down(t);
}
}
int main()
{
for(int i=5;i;i--) down(i);
for(int i=1;i<=10;i++)
{
cout<<h[1]<<" ";
h[1]=h[sizee--];
down(1);
}
return 0;
}