冒泡排序
基本思想:
通过比较相邻两个元素的大小进行互换排序
每趟排序至少有一个元素处在正确的位置上
平均时间复杂度O(n^20),空间复杂度O(1),稳定
代码实现:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100+5;
int a[maxn];
int n;
void BubbleSort(int *a){
for(int i=0;i<n;i++){
for(int j=0;j<i;j++){
if(a[j]>a[j+1]) swap(a[j],a[j+1]);
}
}
}
选择排序
基本思想:
从第一个元素开始依次与其后的元素作比较
每一趟在n-i+1(i=0,1,2,···n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录
平均时间复杂度O(n^2),空间复杂度O(1),不稳定
代码实现:
void SelectSort(int *a){
for(int i=0;i<n-1;i++){
int k=i;
for(int j=i+1;j<n;j++){
if(a[i]>a[j]) k=j;
}
if(k!=i) swap(a[i],a[k]);
}
}
插入排序:针对有序序列
直接插入排序
基本思想:
从第二个元素位置逐个开始插入
每插入一个元素得到的序列均为有序序列
平均时间复杂度O(n^2),空间复杂度O(1),稳定
代码实现:
void StraightInsertSort(int *a){
for(int i=1;i<n;i++){
int temp=a[i];
int j=0;
for(j=i;j>0;j--){
if(a[j-1]>temp){ //元素后移
a[j]=a[j-1];
}
else break;
}
a[j]=temp;
}
}
希尔排序
基本思想:
又名缩小增量排序,一种优化的插入排序
先将序列分割,分别直接插入排序,最后对全体直接插入排序
平均时间复杂度O(n^1.3),空间复杂度O(1),不稳定
代码实现:
void ShellSort(int *a){
int h=1;
while(h<n/3){ //确定增量范围公式
h=h*3+1;
}
while(h>=1){
for(int i=h;i<n;i++){
int temp=a[i];
int j=0;
for(j=i;j<n&&a[j-h]>temp;j-=h){
a[j]=a[j-h]; //元素后移
}
a[j]=temp; //找到插入位置
}
h/=3;
}
}
二分插入排序
基本思想:
每次通过折半查找确定目标元素的插入位置,一定程度上减少元素移动次数
确定好插入位置后,只需依次实现元素后移
平均时间复杂度O(n^2),空间复杂度O(1),稳定
代码实现:
int binarySerach(int *a,int i){ //寻找插入位置
int lowindex=0;
int highindex=i-1;
int mid=0;
while(lowindex<=highindex){
mid=(lowindex+highindex)/2;
if(a[i]>=a[mid])
lowindex=mid+1;
else
highindex=mid-1;
}
return lowindex;
}
void binaryInsertSort(int *a){
for(int i=1;i<n;i++){
int temp=a[i];
int k=binarySerach(a,i); //折半查找
for(int j=i-1;j>=k;j--){ //元素后移
a[j+1]=a[j];
}
a[k]=temp; //k为插入位置
}
}
快速排序
基本思想:
通过一趟排序将原记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,再分别对两部分进行排序
平均时间复杂度O(nlogn),空间复杂度O(nlogn),不稳定
代码实现:
int quickSort(int *a,int low,int high){ //一趟快排
//low=0,high=n-1;
int temp=a[low]; //基准数据
while(low<high){
while(temp<=a[high]&&low<high) //当基准数据小于后面的元素时,右值索引-1
--high;
a[low]=a[high]; //不然移动后面的元素到前面
while(temp>=a[low]&&low<high) //当基准数据大于前面的元素时,左值索引+1
++low;
a[high]=a[low]; //不然移动前面的元素到后面
}
a[low]=temp; //确定基准数据位置
return low;
}
void QuickSort(int *a,int low,int high){
int key=0;
if(low<high){
key=quickSort(a,low,high);
//分别对每一部分快排
quickSort(a,low,key-1);
quickSort(a,key+1,high);
}
}
归并排序
基本思想:
将两个以上的有序序列合并为一个有序序列,为多路归并排序
平均时间复杂度O(nlogn),空间复杂度O(n),稳定
代码实现:
void merge(int *a,int first,int mid,int last){ //合并两个有序序列
int temp[n]; //开辟临时数组
int i=first,j=mid+1;
int m=mid,n=last;
int k=0;
//填充临时数组
while(i<=m&&j<=n){
if(a[i]<=a[j])
temp[k++]=a[i++];
else
temp[k++]=a[j++];
}
//将a中剩余的元素依次放进临时数组中
while(i<=m) temp[k++]=a[i++];
while(j<=n) temp[k++]=a[j++];
for(int i=0;i<k;i++){
a[first+i]=temp[i];
}
}
void mergeSort(int *a,int first,int last){
if(first<last){
int mid=(first+last)/2;
mergeSort(a,first,mid);
mergeSort(a,mid+1,last);
merge(a,first,mid,last);
}
}
堆排序
基本思想:
根据原数组建立初始堆进而调整形成大(小)根堆,最后通过层序遍历实现对数组关键字的排序
只要一个记录大小的辅助空间,每个待排序记录仅占有一个存储空间
平均时间复杂度O(nlogn),空间复杂度O(1),不稳定
代码实现:
void maxHeapDown(int *a,int start,int end){ //大根堆,初始堆为元素按层次插入形成的
int c=start; //当前节点位置
int l=2*c+1; //左孩子位置
int temp=a[c];
for(;l<=end;c=l,l=2*l+1){
if(l<end&&a[l]<a[l+1]) //寻找左右孩子中的较大值
l++;
//确保当前节点为最大值
if(temp>=a[l])
break;
else{
a[c]=a[l];a[l]=temp;
}
}
}
void heapSortAsc(int *a,int n){ //升序
for(int i=n/2-1;i>=0;i--){
maxHeapDown(a,i,n-1); //得到最大二叉堆
}
for(int i=n-1;i>0;i--){
swap(a[0],a[i]); //交换后,a[i]是a[0...i]中最大的
maxHeapDown(a,0,i-1); //调整a[0...i-1],使得a[0...i-1]仍然是一个最大堆
}
}
void minHeapDown(int *a,int start,int end){ //小根堆
int c=start;
int l=2*c+1;
int temp=a[c];
for(;l<=end;c=l,l=2*l+1){
if(l<end&&a[l]>a[l+1])
l++;
if(temp<=a[l])
break;
else{
a[c]=a[l];a[l]=temp;
}
}
}
void heapSortDesc(int *a,int n){ //降序
for(int i=n/2-1;i>=0;i--){
minHeapDown(a,i,n-1);
}
for(int i=n-1;i>0;i--){
swap(a[0],a[i]);
minHeapDown(a,0,i-1);
}
}
主函数实现:
int main(){
cin>>n;
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
//BubbleSort(a);
//SelectSort(a);
//StraightInsertSort(a);
//binaryInsertSort(a);
//ShellSort(a);
//QuickSort(a,0,n-1);
//heapSortAsc(a,n);
//mergeSort(a,0,n-1);
for(int i=0;i<n;i++){
if(i<n-1) printf("%d ",a[i]);
else printf("%d\n",a[i]);
}
return 0;
}
代码均已正确验证过