O(n^2)
void InsertSort(int A[],int n){
int i,j,temp;
for(i=1;i<n;i++){
if(A[i]<A[i-1]){
temp=A[i];
for(j=i-1;j>=0&&A[j]>temp;--j){
A[j+1]=A[j]; // 从后往前检查,比当前元素大的右移
}
A[j+1]=temp;
}
}
}
d
的元素组成同一个子表,对各个子表分别进行直接插入排序,缩小增量d
,直到d=1
为止void ShellSort(int A[],int n){
int i,j,temp,d;
for(d=n/2;d>=1;d=d/2){
for(i=d;i<n;i++){
if(A[i]<A[i-d]){
temp=A[i];
for(j=i-d;j>=0&&A[j]>temp;j-=d){
A[j+d]=A[j]; // 检查前面比当前元素大的右移
}
A[j+d]=temp;
}
}
}
}
O(n^2)
void BubbleSort(int A[],int n){
int i,j,temp,flag;
for(i=0;i<n-1;i++){
flag=false;
for(j=n-1;j>i;j--){
if(A[j]<A[j-1]){ //相等不交换保持稳定
temp=A[j];
A[j]=A[j-1];
A[j-1]=temp;
flag=true;
}
}
if(flag==false)
return; //本趟遍历后没有发生交换,说明已经有序
}
}
pivot
划分待排序表low
和high
向中间移动,将小于pivot
的元素放到左边,大于pivot
的元素放到右边,pivot
元素放到最终位置上,再对左右递归O(log_2n)
O(n)
O(log_2n)
O(nlog_2n)
int Partition(int A[],int low,int high){
int pivot=A[low];
while(low<high){
while(low<high&&A[high]>=pivot){
--high;
}
A[low]=A[high]; // 比枢轴小的元素移动到左边
while(low<high&&A[low]<=pivot){
++low;
}
A[high]=A[low]; // 比枢轴大的元素移动到右边
}
A[low]=pivot;
return low;
}
void Quicksort(int A[],int low,int high){
if(low<high){ //递归跳出条件
int pivotpos=Partition(A,low,high);
Quicksort(A,low,pivotpos-1);
Quicksort(A,pivotpos+1,high);
}
}
O(n^2)
void Selectsort(int A[],int n){
int i,j,temp,min;
for(i=0;i<n-1;i++){
min=i;
for(j=i+1;j<n;j++){
if(A[j]<A[min]){
min=j; //得到最小关键字的索引
}
}
if(min!=i){
temp=A[min];
A[min]=A[i];
A[i]=temp;
}
}
}
i<=⌊n/2⌋
O(n)
O(nlog_2n)
//建立大根堆
void BuildMaxHeap(int A[],int len){
int i;
for(i=len/2;i>0;i--){ //从后往前调整所有非终端节点
HeadAdjust(A,i,len);
}
}
//将以k为根的子树调整为大根堆
void HeadAdjust(int A[],int k,int len){
int i;
A[0]=A[k]; //A[0]暂存防止覆盖
for(i=2*k;i<=len;i*=2){
if(i<len&&A[i]<A[i+1]){
i++; //获取左右孩子中更大的
}
if(A[0]>A[i])
break;
else{
A[k]=A[i]; //A[i]调整到双亲结点上
k=i; //向下继续筛选
}
}
A[k]=A[0]; //注意此时k值已经改变,为该节点最终位置
}
// 堆排序
void HeapSort(int A[],int len){
BuildMaxHeap(A,len);
int temp;
for(int i=len;i>1;i--){
temp=A[i];
A[i]=A[1];
A[1]=temp; //堆顶元素和堆底元素互换
HeadAdjust(A,1,i-1); //把剩余待排元素整理为大根堆
}
}
O(n)
O(nlog_2n)
int *B=(int *)malloc((n+1)*sizeof(int)); // 辅助数组B
void Merge(int A[],int low,int mid,int high){// mid分割两个待归并序列
for(int k=low;k<=high;k++){
B[k]=A[k]; //复制到辅助数组中
}
int i,j,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++];
while(j<=high){
A[k++]=B[j++];
}
}
void MergeSort(int 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); //归并
}
}
n
:待排元素个数d
:单个元素分量的个数rd
:基数,每个分量的取值范围k
均由d
个分量构成,且每个分量都是单独的关键字MSD
–逐层分割成若干子序列LSD
–不必分成若干子实现排序序列,不通过关键字比较,通过“分配”+“收集”实现排序d
位(或组)LSD
方法),做d
趟分配O(n)
和收集O(rd)
O(rd)
O(d(n+rd))
排序算法 | 最好时间复杂度 | 平均时间复杂度 | 最坏时间复杂度 | 空间复杂度(平均) | 是否稳定 |
---|---|---|---|---|---|
直接(折半)插入排序 | O(n) | O(n2) | O(n2) | O(1) | 稳定 |
希尔排序 | - | - | - | O(1) | 不稳定 |
冒泡排序 | O(n) | O(n2) | O(n2) | O(1) | 稳定 |
快速排序 | O(nlog2n) | O(nlog2n) | O(n2) | O(log2n) | 不稳定 |
简单选择排序 | O(n2) | O(n2) | O(n2) | O(1) | 不稳定 |
堆排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(1) | 不稳定 |
归并排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(n) | 稳定 |
基数排序 | O(d(n+rd)) | O(d(n+rd)) | O(d(n+rd)) | O(rd) | 稳定 |
规律总结
根据关键字分布情况选择排序方法