一、插入排序
插入排序算法将数组分为已排序和未排序部分:每次循环都会在已排序部分找到未排序部分开头元素的位置,将其插入。插入排序算法的时间复杂度为O(n²),但是如果数据是相对有序的,插入排序会非常高效。
void insertSort(int arr[],int len){
//外层循环,用于遍历未排序部分,初始时假设下标为0的部分是已排序的
for(int i=1;i<len;i++){
//存储未排序部分的开头元素
int v=arr[i];
//内层循环,用于在已排序部分插入v
int j=i-1;
while(j>=0&&arr[j]>v){
//在已排序部分,将所有比v大的元素向后移动一个单位
arr[j+1]=arr[j];
j--;
}
//将v插入空位
arr[j+1]=v;
}
}
二、冒泡排序
冒泡排序比较相邻的两个元素,从局部减少逆序数,时间复杂度为O(n²)。
void bubbleSort(int arr[],int len){
//每次i循环结束都会固定一个元素的位置,因此j=i+1
for(int i=0;i<len-1;i++){
//依次比较相邻的元素
for(int j=i+1;j<len;j++){
if(arr[i]>arr[j]){
//交换逆序的元素
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
}
}
三、选择排序
选择排序和插入排序一样,也是将数组分为了未排序和已排序两个部分,每次从未排序部分选择一个最小的元素放到已排序部分的下一个位置。
void selectSort(int arr[],int len){
for(int i=0;i<len-1;i++){
int min=i;
for(int j=i+1;j<len;j++){
if(arr[j]<arr[min]){
min=j;
}
}
int temp=arr[min];
arr[min]=arr[i];
arr[i]=temp;
}
}
四、希尔排序
希尔排序是插入排序的升级版,扩大了插入排序处理相对有序的数据的优势。希尔排序每次以间隔为g的元素进行插入排序。如果g(n+1)=3g(n)+1时,希尔排序的时间复杂度为O(n^1.25)
//存储g的取值
vector<int> gArr;
void insertSort(int arr[],int len,int g){
//假设[g,len]的元素是未排序的
for(int i=g;i<len;i++){
int v=arr[i];
//假设[0,i-g]的元素是已排序的
int j=i-g;
while(j>=0&&arr[j]>v){
arr[j+g]=arr[j];
//插入数据后[0-j]的数据不再是有序,此时再以间隔为g比较新插入的元素
j-=g;
}
arr[j+g]=v;
}
}
void shellSort(int arr[],int len){
//生成间隔g
for(int i=1;i<=len;){
gArr.push_back(i);
i=i*3+1;
}
//逆序指定g
for(int i=gArr.size()-1;i>=0;i--){
insertSort(arr,len,gArr[i]);
}
}