zoukankan      html  css  js  c++  java
  • 基础算法:排序算法

    话不多说,上代码

    #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
    ",++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
    *****************/
  • 相关阅读:
    强烈推荐好用的文本编辑器Notepad++
    MSP430学习笔记9PS2键盘解码
    MSP430学习笔记8ST7920 12864液晶显示并行接口
    MSP430学习笔记74*4键盘的对应数码管显示
    MSP430学习笔记6动态数码管的显示
    MSP430寄存器中文注释
    MSP430学习小结3MSP430基本时钟模块
    ST7920 12864液晶图片取模,显示你想显示的图片。
    MSP430学习小结2程序主体结构安排及低功耗转载
    Windows Phone开发之路(4) XAML基础(上)
  • 原文地址:https://www.cnblogs.com/DevilInChina/p/9375246.html
Copyright © 2011-2022 走看看