基础算法:排序算法

话不多说,上代码

 

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <random>
#include <string.h>
#define N 10000500
long long beg;
int cnt,n;
void show_time(){
    long long now = clock();
    printf("Case #%d:%12.1f ms\n",++cnt,1.0*(now - beg)/CLK_TCK*1000);
}
void swap(int *a,int *b){
    *a^=*b;
    *b^=*a;
    *a^=*b;
}

///称这两个函数为比较函数,函数名即相当于指针,将其写入排序算法中,实现代码复用
char Ascending(int a,int b){ return a<b;}
char Descending(int a,int b){ return a>b;}//没有bool我也很无奈

/**
 * @param s:开始指针 e:结束指针
 * @param cmp 指向函数的指针
 * @note 快速排序:平均时间复杂度 O(n*ln(n))  最坏情况(倒序)O(n^2)
 */
void quick_sort(int *s,int *e,char (*cmp)(int ,int )){///对于左闭右开的区间中的数据(int)进行排序
///中心思想:递归,分治求解
    int *i = s,*j = e-1;
    if(i>j)return;
    int key = *i;///选择开始位置为"标记值"
    while (i!=j){
        while(!cmp(*j,key)&&i<j)j--;///从后往前 *j 不小于 key 说明从j开始后面的元素都>=key,否则结束循环
        while(!cmp(key,*i)&&i<j)i++;///与上同理
        if(i<j){                    ///到这里我们找到了位置不对的一组元素
            swap(i,j);
        }
    }
    *s = *i;///把key放到适当的位置,这时满足key左边的元素均不大于(小于)key,右边元素均不小于(大于)key
    *i = key;
    quick_sort(s,i,cmp);///对key左,右侧进行同样
    quick_sort(i+1,e,cmp);
}

/**
 * @param s:开始指针 e:结束指针 k:临时储存
 * @param cmp 指向函数的指针
 * @note 归并排序:时间复杂度 O(n*ln(n))
 * @note 相较快速排序更加稳定
 * @note 可以通过修改程序在 O(n*ln(n))时间内找出数据的逆序数(传统需要O(n^2))
 */
void merge(int *s,int *e,char (*cmp)(int,int),int *k){
    int *ori_beg = s;
    int *copy = k;
    int *mid = (e-s)/2+s;///将mid左右两侧的元素在线性时间内合并为有序的,要求:左右两侧区间内均有序
    int *i = s,*j = mid+1;
    while (i<=mid&&j<=e){
        if(cmp(*i,*j)){
            *k=*i;
            ++i,++k;
        }
        else {
            *k = *j;
            ++k,++j;
        }
    }
    while(i<=mid){*k=*i,++i,++k;}
    while (j<=e){*k=*j,++j,++k;}
    while (ori_beg<=e){*ori_beg=*copy,++copy,++ori_beg;}
}
void merge_sort(int *s,int *e,char (*cmp)(int ,int),int *store){
    if(s>=e)return;
    int *mid = (e-s)/2+s;
    merge_sort(s,mid,cmp,store);
    merge_sort(mid+1,e,cmp,store);
    merge(s,e,cmp,store);///经过上面的操作我们假设左右两边都已经排序完毕,然后进行归并操作
}
void stable_sort(int *s,int *e,char (*cmp)(int ,int)){
    ///中心思想:分治递归
    int *tmp = (int *)malloc((e-s)* sizeof(int));///申请额外的空间用来支持排序
    merge_sort(s,e-1,cmp,tmp);///左右均为闭区间,这里有讲究
    free(tmp);
}

/**
 * @note 参考了 CSDN
 * @note 幂增长复杂度 中等数据规模有较好的表现
 */
void shell_sort(int *s,int *e,char (*cmp)(int ,int)){
    ///和插入排序放在一起理解,我们发现插入排序一次只移动一个单位,所以就更改移动的步长,慢慢减小以达到减少时间开销的目的
    int dis_seq = 1,tmp;
    int maxs = (e - s)/3;
    int i,*j,*k;
    while(dis_seq<maxs){
        dis_seq = dis_seq*3+1;///计算增量区间,有特别的讲究,要求元素非质
    }
    maxs = e-s;
    while(dis_seq>0){///最后一个递增步长是1,否则很大概率排序不会成功
        for(i = dis_seq ; i < maxs ; ++i){
            tmp = *(s+i);
            j = s+i;
            k = s+dis_seq-1;
            while(j>k&&!cmp(*(j-dis_seq),tmp)){
                *j = *(j-dis_seq);///将*j(tmp)插入到合适位置
                j-=dis_seq;
            }
            *j = tmp;
        }
        dis_seq = (dis_seq-1)/3;
    }
}


void bubble_sort(int *s,int *e, char (*cmp)(int,int)){
    int *i,*j = e-1;///不过多解释,较传统冒泡有两个特别的优化
    int *last = e;
    char not_order;
    do{
        not_order = 0;/// First optimize ,we don't need to sort if it is ordered.
        for(i = s ; i < j ; ++i){
            if(cmp(*(1+i),*i)){
                swap(i,i+1);
                not_order = 1;
                last = i;
            }
        }
        j = last;/// Second optimize ,we don't need to sort if the past sequence are order.
    }while (not_order);
}

void selection_sort(int *s,int *e,char (*cmp)(int ,int)){
    int *i,*j,*mark;///正常思维下的排序
    int key;
    for(i = s ; i<e ; ++i){
        key = *i;
        mark = i;
        for(j = i+1 ; j < e ; ++j){
            if(cmp(*j,key)) {
                key = *j;
                mark = j;
            }
        }
        if(key!=*i)swap(i,mark);
    }
}

void insertion_sort(int *s,int *e,char (*cmp)(int,int)){
    int *i,*j,key;///和希尔(shell)排序一样
    for(i = s+1 ; i!=e ; ++i){
        j = i;
        key = *i;
        while (j>s&&!cmp(*(j-1),key)){
            *j = *(j-1);
            j--;
        }
        *j = key;
    }
}

///打印信息
void show(int *a,int *b){
    while (a!=b){
        printf("%d ",*a);
        ++a;
    }
}
int num[N];
int ori[N];
void init(int n){
    memcpy(num,ori,n* sizeof(int));
    beg = clock();
}
int main(){
    srand(time(NULL));
    while (scanf("%d",&n),n){
        for(int i = 0 ; i < n ; ++i){
            ori[i] = rand()%n+1;
        }
        cnt = 0;

        init(n);
        quick_sort(num,num+n,Ascending);
        show_time();

        init(n);
        stable_sort(num,num+n,Ascending);
        show_time();

        init(n);
        shell_sort(num,num+n,Ascending);
        show_time();

        init(n);
        insertion_sort(num,num+n,Ascending);
        show_time();

        init(n);
        selection_sort(num,num+n,Ascending);
        show_time();

        init(n);
        bubble_sort(num,num+n,Ascending);
        show_time();

    }
}

/**
 * n(ln(n))
 * 1 快速排序
 * 2 归并排序
 * 介于线性和二次方之间
 * 3 希尔排序
 * 二次方复杂度
 * 4 插入排序
 * 5 选择排序
 * 5 冒泡排序
 */
/*****************
TEST one:
1000000
Case #1:       187.0 ms
Case #2:       188.0 ms
Case #3:       391.0 ms

TEST two:
10000000
Case #1:      4172.0 ms
Case #2:      2136.0 ms
Case #3:     11986.0 ms

TEST three:
10000
Case #1:         0.0 ms
Case #2:         0.0 ms
Case #3:         0.0 ms
Case #4:        62.0 ms
Case #5:       109.0 ms
Case #6:       344.0 ms

TEST four:
100000
Case #1:        15.0 ms
Case #2:        15.0 ms
Case #3:        32.0 ms
Case #4:      6938.0 ms
Case #5:     10611.0 ms
Case #6:     35866.0 ms
*****************/

 

posted @ 2018-07-27 00:35  DevilInChina  阅读(179)  评论(0编辑  收藏  举报