qsort与算法竞赛

算法竞赛中,排序是非常重要的内容。无论是可以用来算逆序对的归并排序,还是广泛运用在贪心算法里的快速排序,对它们的熟练掌握,都会让程序拥有更高的效率。在这篇文章里,我想说说自己对qsort的一点思考。

1. 语法--以单关键字排序为例

C语言的stdlib.h中有qsort的库函数,可以直接使用,非常方便。

void qsort(void * base, size_t num, size_t size, int (*comparator)(const void *, const void *));

如何使用它:

#include
int a[1001];
int cmp( const void * x, const void * y){
    if (*(int *)x < *(int *)y) return -1; //格式可以记为 *(类型名 *) 变量名
    else return 1;
}

int main(void){
    int i,n;
    cin>>n;
    for (int i=1; i<=n; i++) cin>>a[i];
    qsort(a+1, n, sizeof(a), cmp); //数组是从a[1]开始存的
    for (int i=1; i<=n; i++) cout<

总结一下,qsort的语法是,

qsort(需要排序的数组的起始内存地址位置,元素个数,单个元素大小,比较函数);

比较函数cmp的特点是,如果返回值为负数,就不做修改;如果返回值为正数,就要交换两数位置。所以qosrt本质上是一个基于比较与交换的算法,其根据比较函数的返回值来决定是否要对元素进行交换。
同时也想提一下比较函数中的 " const void * ",在大名鼎鼎的《算法竞赛入门经典》(以后我会根据大家的习惯把它称为‘紫书’)一书中,刘汝佳老师称它为“指向函数的‘万能’指针”:“它可以通过强制类型转化变成任意类型的指针”。在函数中,"*(int *) x" 会将“void *”类型转化成“int *”类型,再用“*” 运算符提取出对应的元素。

(碎碎念:用markdown打星号好不方便……一不小心就变成斜体字了2333)

2. 双关键字排序

双关键字排序一般用qsort+stuct来实现。当我们有两个变量需要同时进行比较时,双关键字排序会起到非常重要的作用。
还是想啰嗦一下,在我们遇到需要在移动变量1的同时移动变量2这种情况时,结构体是更为方便的选择。因为当a[1].x在比较之后被确定需要swap之时,a[1].y也会随着结构体的变动而变动。

一言不合就上代码:

struct aa{ int x,y; } a[N];
int cmp(const void * x, const void * y){
    aa p1 = *(aa *) x; aa p2 = *(aa *) y;
    if (p1.x < p2.x) return -1;
    if (p1.x > p2.x) return 1;
    if (p1.y < p2.y) return -1;
    return 1;
}
qsort(a+1, n, sizeof(aa), cmp);
3. 多关键字排序

多关键字排序本质上和双关键字排序完全相同。这里附上三关键字排序的代码。理解之后,无论有多少个关键字,都会很容易写出来。

struct aa{ int x,y,z; } a[N];
int cmp(const void * x, const void * y){
    aa p1 = * (aa *) x; aa p2 = * (aa *) y;
    if (p1.x < p2.x) return -1;
    if (p1.x > p2.x) return 1;
    if (p1.y < p2.y) return -1;
    if (p1.y > p2.y) return 1;
    if (p1.z < p2.z) return -1;
    return 1;
}
4. 例题

最后想放例题以详细说明qsort在实战中的使用。感兴趣的同学,不妨先去试试看,再来看我的代码。当然,如果你们有更好的方法或者更优美的代码,也欢迎交流~:)

OnlineJudge: UVa
Problem #: 1339
#include
#include
#include
using namespace std;
char a[105], b[105];

int cmp(const void *x, const void *y){
    if (*(int *)x < *(int *)y) return -1;
    else return 1;
}
int main(void){
    //freopen("uva1339.txt","r",stdin);
    while(scanf("%s%s", a, b) != EOF){
        int n = strlen(a);
        
        int cnt1[26]; int cnt2[26];
        memset(cnt1,0,sizeof(cnt1)); memset(cnt2,0,sizeof(cnt2));

        for(int i=0;i
OnlineJudge: UVa
Problem #: 1587
#include
#include
using namespace std;

struct aa{
    int x,y;
}a[7];

int cmp(const void *x, const void *y){
    aa p1=*(aa*)x; aa p2=*(aa*)y;
    if(p1.xp2.x)return 1;
    if(p1.ya[0].y) swap(a[0].x,a[0].y);
        for(int i=1;i<6;i++){
            scanf("%d%d",&a[i].x,&a[i].y);
            if(a[i].x>a[i].y) swap(a[i].x,a[i].y);
        }
        
        qsort(a,6,sizeof(aa),cmp);
        
        int error = 0;
        for(int i=0; i<3; i++)
        {
            if(a[i*2].x!=a[i*2+1].x || a[i*2].y!=a[i*2+1].y)
            {
                error = 1;
                break;
            }
        }
        
        if(!error && a[0].x==a[2].x && a[0].y==a[4].x && a[2].y==a[4].y)
            printf("POSSIBLE\n");
        else
            printf("IMPOSSIBLE\n");
    }
    return 0;
}

特别鸣谢:

我的第一位也是迄今为止唯一的算法老师:弟弟 (NOIP与ACM大神一枚)

参考资料:
  • 《算法竞赛入门经典》刘汝佳

你可能感兴趣的:(qsort与算法竞赛)