目录
插入排序
直接插入排序
//直接插入排序,时间O(n²),空间O(1),稳定
void InsertSort(ElemType A[],int n){
int i,j;
for(i=2;i<=n;i++) //将第一个元素视为一个有序表,从第二个元素开始依次将后续元素插入有序表
if(A[i-1]>A[i]){ //判断当前A[i]关键码在有序表后是否已经满足
A[0]=A[i]; //A[0]位置本身不存储元素,用来放置排序时的待插入元素
for(j=i-1;A[0]<A[j];--j) //从后往前只要满足待调整元素小于当前元素就后挪,直到找到带插入位置
A[j+1]=A[j]; //往后挪置
A[j+1]=A[0]; //待插入元素插入有序表中相应的位置
}
}
希尔排序
//希尔排序,最坏O(n²),空间O(1),不稳定(当相同关键字被划分到不同子表时,会改变他们的相对次序)
void ShellSort(ElemType A[],int n){
int dk,i,j;
for(dk=n/2;dk>=1;dk=dk/2){ //dk是比较元素时的"增量"
//此处和直接插入排序一样,就是把1换成了dk,记忆时可以同直接插入一起比较记忆
for(i=dk+1;i<=n;++i){ //从1+dk的位置开始,遍历后面每一个元素
if(A[i-dk]>A[i]){
A[0]=A[i];
for(j=i-dk; j>0 && A[0]<A[j];j=j-dk)
A[j+dk]=A[j];
A[j+dk]=A[0];
}
}
}
}
折半插入
//折半插入排序,减少了比较次数,元素移动次数未变,时间复杂度仍为O(n²),稳定
void BinaryInsertSort(ElemType A[],int n){
int i,j,low,high,mid;
for(i=2;i<=n;i++){
A[0]=A[i];
low=1;high=i-1;
while(low<=high){//在有序表中通过折半比较找到待插入位置
mid=(low+high)/2;
if(A[0]<A[mid]) high=mid-1;//待插入元素比中间位置小,则在有序表左半部分继续查找
else low=mid+1;
}
for(j=i-1;j>=high+1;--j) //与直接插入排序相比,终止条件变了,因为已经知道待插入位置了,为high+1处
A[j+1]=A[j];
A[j+1]=A[0];
}
}
交换排序
快速排序
//快速排序 时间O(nlogn),空间O(logn),不稳定(若右端有两个相同关键字,且都比枢纽小,则相对位置发生变化)
int Partition(ElemType A[],int low,int high){
ElemType pivot=A[low]; //A[low]挖一个空,右边的比枢纽小的放到左边low处,左边的比枢纽大的放右边high处,交替进行
while(low<high){
while(low<high && pivot<=A[high]) --high; //默写代码时注意,这里low<high又重复了一次
A[low]=A[high];
while(low<high && A[low]<=pivot) ++low;
A[high]=A[low];
}
A[low]=pivot;
return low;
}
void QuickSort(ElemType A[],int low,int high){
if(low<high){
int pivotpos=Partition(A,low,high);//排序一次,并返回枢纽最终位置,将表分为两部分,对左右分别再排序
QuickSort(A,low,pivotpos-1);//对左边的表进行排序
QuickSort(A,pivotpos+1,high);//对右边的表进行排序
}
}
Partition函数:(对表按照某个枢纽进行一次排序,并返回枢纽位置)
将A[low]作为枢纽,最终将他插到表中间的某个位置,使得枢纽左边的元素比枢纽小,右边的元素比枢纽大。故high位置的元素若已经满足就high--,直到一个元素不符合,即比枢纽小,那它就要放到枢纽左边去,放到low的位置。若low位置的元素已经满足条件就low++,直到一个元素不符合,即比枢纽大,那它就要放到枢纽右边去,放到high的位置。最终high=low跳出while循环,并将保存的枢纽元素放到A[low]位置,返回枢纽的位置low
QuickSort函数:递归函数,每次递归对表进行一次排序,并利用返回的枢纽位置对左右表再排序
冒泡排序
//冒泡排序,时间O(n²),空间O(1),稳定
void swap(ElemType &a,ElemType &b){
ElemType temp;
temp=a;a=b;b=temp;
}
//此处为获得升序有序序列,每次将最小的元素冒到开头
void BubbleSort(ElemType A[],int n){
for(int i=0;i<n-1;i++){ //冒泡的最终位置
bool flag=false; //是否发生交换的标志
for(int j=n-1;j>i;j--) //j从最后一个元素开始,到冒泡最终位置的后一位
if(A[j-1]>A[j]){ //若构成逆序,即后一个元素小于前一个元素,则交换位置
swap(A[j-1],A[j]);
flag=true;
}
if(flag==false) //未发生交换,则说明序列已经有序
return;
}
}
双冒泡
//双冒泡
void DoubleBubbleSort(ElemType A[],int n){
for(int i=0;i<(n-1)/2;i++){
bool flag=false;
//最小元素冒到表头
for(int j=n-1;j>i;j--)
if(A[j-1]>A[j]){
swap(A[j-1],A[j]);
flag=true;
}
//最大元素冒到表尾
for(int j=0;j<n-1-i;j++) //注意此处终止条件
if(A[j]>A[j+1]){
swap(A[j],A[j+1]);
flag=true;
}
if(flag==false)
return;
}
}
选择排序
简单选择排序
//简单选择排序 时间O(n²),空间O(1),不稳定(涉及交换的四个算法除了冒泡都不稳定)
void SelectSort(ElemType A[],int n){
for(int i=0;i<n-1;i++){ //对前n-1个位置进行变换,每次选择后序元素中最小的元素进行交换
int min=i,j;
for(j=i+1;j<n;j++)
if(A[j]<A[min]) min=j;
if(min!=j) swap(A[i],A[min]);
}
}
堆排序
/**
* 堆排序(大根堆) 时间O(nlogn),空间O(1),不稳定
* 堆可视为完全二叉树,最后一个非叶节点存储在|_n/2_|中
*/
void HeapAdjust(ElemType A[],int k,int len){ //调整堆
A[0]=A[k]; //取出A[k]暂存,将k位置空出来
/*从待调整位置开始往下寻找,*2看其左孩子,与右孩子比大小,
记录较大者位置,判断此时与父节点相比是否需要调整*/
for(int i=2*k; i<=len; i*=2){
if(i<len && A[i]<A[i+1]) //i要<len,因为要判断A[i+1]
i++;
if(A[0]>=A[i]) break; //不需要调整,此时已经是大根堆了
else{
A[k]=A[i];
k=i; //k要后移到较大的子孩子的位置
}
}
A[k]=A[0];
}
void BuildMaxHeap(ElemType A[],int len){ //建立初始堆
for(int i=len/2;i>0;i--)
HeapAdjust(A,i,len);
}
void HeapSort(ElemType A[],int len){ //堆排序
BuildMaxHeap(A,len);
for(int i=len; i>1; i--){ //len-1趟排序,每次挑出一个最大的元素,即堆顶,放到最后,然后将剩下的元素调整
swap(A[i],A[1]); //输出堆顶元素,和堆底元素交换,换到堆的最后(相当于将最大元素输出了),len--,再对剩余元素排序
HeapAdjust(A,1,i-1); //从堆顶开始调整
}
}
二路归并排序
//归并排序 时间O(nlogn)[共需logn趟,每趟n],空间O(n),稳定(merge不改变相对次序)
int n=4;
ElemType *B=(ElemType *)malloc((n+1)*sizeof(ElemType)); //辅助数组
void Merge(ElemType A[],int low,int mid,int high){ //需要mid将A划分为两个子表进行归并
int i,j,k;
for(k=low;k<=high;k++) //将A中元素复制到B中,再从B中比较挑选元素放到A中,A为最后结果
B[k]=A[k];
for(i=low,j=mid+1,k=i; i<=mid && j<=high; k++)
{
if(B[i]<=B[j])
A[k]=B[i++];
else
A[k]=B[j++];
}
while(i<=mid) A[k++]=B[i++]; //子表1中有剩余,则将剩余元素加入到A中
while(j<=high) A[k++]=B[j++];
}
void MergeSort(ElemType A[],int low,int high){ //先划分后归并
if(low<high){
int mid=(low+high)/2; //从中间划分为两个子序列
MergeSort(A,low,mid); //对左边子序列继续划分
MergeSort(A,mid+1,high); //对右边子序列继续划分
Merge(A,low,mid,high); //归并
}
}
基数排序
/**
* 时间O(d(n+r))[d趟,一趟分配O(n),收集O(r)]
* 空间O(r)[r个队列]
* 稳定(不改变相对顺序)
*/