排序算法小结(一)

排序算法的稳定性:

如果一个待排序的序列中,存在2个相等的数,在排序后这2个数的相对位置保持不变,那么该排序算法是稳定的;否则是不稳定的。

稳定的意义:排序算法如果是稳定的,从一个键上排序,然后从另一个键上排序,第一个键排序的结果可以为第二个键排序所用

两个重要定理:

定理1:任意N个不同元素组成的序列平均具有N(N-1)/4个逆序对。

定理2:任何仅以交换相邻两元素来排序的算法,其平均时间复杂度为(N^2)

因此要提高排序算法效率,我们必须:

  1.每次消去不止1个逆序对!

  2.每次交换相隔较远的两个元素!

 

一、冒泡排序:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
#define inf 0x3fffffff
void Bubble_Sort(int num[],int n){
    for(int i=n-1;i>0;i--){
        int flag=0;//如果序列已经有序,不需要再进行比较
        for(int j=0;j<i;j++){
            if(num[j]>num[j+1]){
                swap(num[j],num[j+1]);
                flag=1;
            }
        }
        if(flag==0){
            break;
        }
    }
}
printff(int num[],int n){
    for(int i=0;i<n;i++){
        printf("%d ",num[i]);
    }
    printf("\n");
}
//冒泡排序
//最好情况:O(n);
//最坏情况:O(n^2);
int main(){
    int num[maxn];
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&num[i]);
    }
    Bubble_Sort(num,n);
    printff(num,n);
    return 0;
}

冒泡算法是稳定的算法,因为排序前后相同元素的相对位置不变。

交换的次数等于序列的逆序数(线代第一章有讲)

二、插入排序

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
#define inf 0x3fffffff
void Insertion_Sort(int num[],int n){
    int temp;
    int j;
    for(int i=1;i<n;i++){
        temp=num[i];//未排序元素
        for(j=i;j>0&&temp<num[j-1];j--){
            num[j]=num[j-1];//移出空位
        }
        num[j]=temp;//元素落位
    }
}
void printff(int num[],int n){
    for(int i=0;i<n;i++){
        printf("%d ",num[i]);
    }
    printf("\n");
}
//插入排序
//最好情况:O(n);
//最坏情况:O(n^2);n(n+1)/2;

int main(){
    int num[maxn];
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&num[i]);
    }
    Insertion_Sort(num,n);
    printff(num,n);
    return 0;
}

用一句话理解就是:将未排序的元素插入到已排序的序列中。在插入的过程中,元素往后挪。

交换的次数等于序列的逆序数

三、希尔排序

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
#define inf 0x3fffffff
void Shell_Sort(int num[],int n){
    int j;
    for(int D=n/2;D>0;D/=2){//设置增量(此处增量不互质)
        for(int i=D;i<n;i++){//插入排序
            int temp=num[i];
            for(j=i;j>=D&&temp<num[j-D];j-=D){
                num[j]=num[j-D];
            }
            num[j]=temp;
        }
    }
}
void printff(int num[],int n){
    for(int i=0;i<n;i++){
        printf("%d ",num[i]);
    }
    printf("\n");
}
//希尔排序
//最好情况:O(n);
//最坏情况:O(n^2);

int main(){
    int num[maxn];
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&num[i]);
    }
    Shell_Sort(num,n);
    printff(num,n);
    return 0;
}

 

注:如果增量D不互质,则小增量可能根本不起作用。

  可以用Hibbard增量序列:Dk=2^k-1  (相邻元素互质)

四、选择排序

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
#define inf 0x3fffffff
void Selection_Sort(int num[],int n){
    for(int i=0;i<n;i++){
        int temp=i;
        for(int j=i;j<n;j++){//从i到n中找到最小元,并将其位置赋给temp
            if(num[j]<num[temp]){
                swap(j,temp);
            }
        }
        if(temp!=i){//将未排序部分的最小元交换到有序部分的最后位置
            swap(num[temp],num[i]);
        }
    }
}
void printff(int num[],int n){
    for(int i=0;i<n;i++){
        printf("%d ",num[i]);
    }
    printf("\n");
}
//选择排序
//复杂度:O(n^2)
int main(){
    int num[maxn];
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&num[i]);
    }
    Selection_Sort(num,n);
    printff(num,n);
    return 0;
}

五、堆排序

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3fffffff
const int maxn=1010;
//heap为堆,n为元素个数
int heap[maxn],n=100;
//向下调整  时间复杂度为O(logn)
void downAdjust(int low,int high){
    int i=low,j=i*2;  //i为欲调整结点,j为其左孩子
    while(j<=high){ //存在孩子结点
        if(j+1<=high&&heap[j+1]>heap[j]){//如果存在右孩子结点,且右孩子的值大于左孩子
            j=j+1;      //让j存储右孩子的下标
        }
        if(heap[j]>heap[i]){    //如果孩子中最大权值比欲调整结点i大
            swap(heap[j],heap[i]);  //交换最大权值的孩子与欲调整结点i
            i=j;    //保持i为欲调整结点,j为i的左孩子
            j=i*2;
        }
        else{
            break;  //孩子的权值均比欲调整结点i小,调整结束
        }
    }
}
//建堆 时间复杂度O(n)
void creatHeap(){
    for(int i=n/2;i>=1;i--){//从最后一个非叶子结点开始枚举
        downAdjust(i,n);
    }
}
//删除堆顶元素 时间复杂度O(logn)
void deleteTop(){
    heap[1]=heap[n--];  //用最后一个元素覆盖堆顶元素,并让元素个数减 1
    downAdjust(1,n);    //向下调整堆顶元素
}
//向上调整   时间复杂度为O(logn)
void upAdjust(int low,int high){//对heap数组在[low,high]范围进行向上调整,其中low一般设置为1
//high表示欲调整结点的数组下标
    int i=high,j=i/2;//i为欲调整结点,j为其父亲
    while(j>=low){  //父亲在[low,high] 范围内
        if(heap[j]<heap[i]){    //父亲权值小于欲调整结点i的权值
            swap(heap[j],heap[i]);  //交换父亲和欲调整结点
            i=j;    //保持i为欲调整结点,j为i的父亲
            j=i/2;
        }
        else{
            break;  //父亲权值比欲调整结点i的权值大,调整结束
        }

    }

}
//添加元素   时间复杂度O(logn)
void insert(int x){
    heap[++n]=x;    //让元素个数加 1 ,然后将数组末位赋值为 x
    upAdjust(1,n);  //向上调整新加入的结点 n
}
//堆排序    时间复杂度O(nlogn)
void heapSort(){
    creatHeap();    //建堆
    for(int i=n;i>1;i--){   //倒着枚举,直到堆中只有一个元素
        swap(heap[i],heap[1]);  //交换heap[i]与堆顶
        downAdjust(1,i-1);  //向下调整堆顶
    }
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>heap[i];
    }
    heapSort();
    for(int i=1;i<=n;i++){
        cout<<heap[i]<<" ";
    }
    cout<<endl;
    return 0;
}
//示例:
//5             输入
//3 1 4 5 2     输入
//1 2 3 4 5     输出

详细请看:

六、归并排序

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
#define inf 0x3fffffff

void mort(int num[],int left,int mid,int right){
    int num2[maxn];
    for(int i=left;i<=right;i++){
        num2[i]=num[i];
    }
    int i=left,j=mid+1,k=0;
    while(i<=mid&&j<=right){
        if(num2[i]<=num2[j]){
            num[left+k]=num2[i];
            k++;
            i++;
        }
        else{
            num[left+k]=num2[j];
            k++;
            j++;
        }
    }
    while(i<=mid){
        num[left+k]=num2[i];
        i++;
        k++;
    }
    while(j<=right){
        num[left+k]=num2[j];
        j++;
        k++;
    }
}
void GBsort(int num[],int left,int right){
    if(left>=right){
        return ;
    }
    int mid=(left+right)/2;
    GBsort(num,left,mid);//递归处理左子序列
    GBsort(num,mid+1,right);//递归处理右子序列
    mort(num,left,mid,right);//合并左右子序列
}
void printff(int num[],int n){
    for(int i=0;i<n;i++){
        printf("%d ",num[i]);
    }
    printf("\n");
}
//归并排序
//复杂度:nlogn
int main(){
    int num[maxn];
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&num[i]);
    }
    GBsort(num,0,n-1);
    printff(num,n);
    return 0;
}

 

明天继续。。。

posted @ 2021-04-03 23:03  XA科研  阅读(67)  评论(0编辑  收藏  举报