学习心得:一种不破坏原数组排序的排序方法——指针数组|小白编程题——初进ACM

指针数组在排序算法中的应用

基本思路

排序算法虽然好用,但会破坏掉原有数组的顺序。有时候,我们并不想这样(例如在使用结构体、共用体)。

这时候,我们可以创建一个指针数组,分别指向原数组中的每个元素,对指针数组进行排序。基本思想就是在冒泡排序时定义的中间临时变量是一个指针变量,冒泡时交换的是指针,即可在不破坏原有数组的顺序下得到排序结果。若想调用排序前的直接调用原数组,若想调用排序后的数组,只需要对排序后的指针数组进行解引用即可。

代码实现

以下是以最简单的排序方法——冒泡排序法实现的C语言代码:

//指针数组排序
#include
int main(){
    int m[10]={10,80,89,66,54,1708,108,1816,1024,1712};
    int *p[10];
    printf("before:\n");
    printf("ori arr:\n");
    for(int i=0;i<10;i++){
        printf("%d\t",m[i]);
    }
    printf("pointer arr:\n");
    for(int i=0;i<10;i++)
        p[i]=&m[i];
    for(int i=0;i<10;i++){
        printf("%d(%p)\t",*p[i],p[i]);
    }
    //开始排序(冒泡法)
    for(int j=0;j<10-1;j++){//冒泡轮数=已排序指针个数
        for(int i=0;i<10-1-j;i++){
            if(*p[i]>*p[i+1]) {//冒泡:和相邻项做比较
                int *t;
                t=p[i+1];
                p[i+1]=p[i];
                p[i]=t;
            }
        }
    }
    printf("after:\n");
    printf("ori arr:\n");
    for(int i=0;i<10;i++){
        printf("%d\t",m[i]);
    }
    printf("pointer arr:\n");
    for(int i=0;i<10;i++){
        printf("%d(%p)\t",*p[i],p[i]);
    }
    return 0;
}

例:1082-初进ACM

下面以本题为例,请大家感受一下指针数组在结构体中的应用。

描述

欢迎大家来参加计算机科学与工程学院ACM竞赛;既然来参加比赛,想必也知道,比赛的排名的规则吧;

首先我们按出题量排名,出题量多者,排名靠前,其次出题量一样是看出题的时间,但当时间一样时,看你的姓名的字典序排名,但名次一样;当然提交错误,会有惩罚,每提交错一次,罚时20分钟;(提示:一共有5道题,题目没有通过不罚时)

输入

首先输出一个整数n,代表n个人;(0 < n < 100)

再有n行,每一行有一个人名,(每个人名都是由小写字母组成,且长度不超过10)在人名后面有10个数,前5个数代表出每一道题所用的时间(时间的不超过120.),后5个数代表每一道题提交错误的次数(错误次数不超过10.);当时间为0时,说明这道题没做出来;

输出

输出排名,每一个人一行;

输入样例 1 
2
wula 5 10 0 0 0 0 1 3 0 0
sese 18 5 17 0 0 2 0 2 0 0
4
bsd 0 0 1 5 9 1 1 1 2 2
aerwt 0 3 0 7 25 10 1 1 1 2
ciuu 10 20 30 40 50 2 3 4 5 6
dyrtu 11 22 33 44 55 1 2 3 3 6
输出样例 1
1st sese
2st wula
1st dyrtu
2st ciuu
3st aerwt
3st bsd
#include 
#include
int main() {
    int n;
    while (scanf("%d", &n) != EOF) {
        //对每个ACMer的名字、AC数、AC时间、WA数的数据获取,并计算加入罚时后的总时间
        struct acm {
            char name[11];
            int single[5];
            int wa[5];
            int ac;
            int sum;
            int rank;
        } stu[n];
        memset(stu, 0, sizeof(stu));//初始化结构体数组为0,避免被装入垃圾数据
        struct acm *p[n];
        for (int i = 0; i < n; i++)
            p[i] = &stu[i];
        for (int i = 0; i < n; i++) {
            scanf("%s", stu[i].name);
            for (int k = 0; k < 5; k++) {
                scanf("%d", &stu[i].single[k]);
                if (p[i]->single[k] != 0) {
                    p[i]->ac++;
                }
                p[i]->sum += p[i]->single[k];
            }
            for (int k = 0; k < 5; k++) {
                scanf("%d", &stu[i].wa[k]);
                if (p[i]->single[k] != 0) {
                    p[i]->sum += (p[i]->wa[k] * 20);
                }
            }
        }
        //下面对AC数进行指针排序
        for (int j = 0; j < n - 1; j++) {
            for (int i = 0; i < n - 1 - j; i++) {
                if (p[i]->ac < p[i + 1]->ac) {
                    struct acm *t;
                    t = p[i + 1];
                    p[i + 1] = p[i];
                    p[i] = t;
                } else if (p[i]->ac == p[i + 1]->ac) {
                    if (p[i]->sum > p[i + 1]->sum) {
                        struct acm *t;
                        t = p[i + 1];
                        p[i + 1] = p[i];
                        p[i] = t;
                    } else if (p[i]->sum == p[i + 1]->sum) {
                        if (strcmp(p[i]->name, p[i + 1]->name) > 0) {
                            struct acm *t;
                            t = p[i + 1];
                            p[i + 1] = p[i];
                            p[i] = t;
                        }
                    }
                }
            }
        }
        int count = 1; // 初始化计数器为1
        for(int i=0;irank=1;
            }else{
                if(p[i]->ac==p[i-1]->ac && p[i]->sum==p[i-1]->sum){
                    p[i]->rank=p[i-1]->rank; // 如果当前元素与前一个元素并列,则他们的排名相同
                    count++; // 并列的元素数量加一
                }else{
                    p[i]->rank=p[i-1]->rank+count; // 如果当前元素与前一个元素不并列,则他的排名应该是前一个元素的排名加上并列的元素数量
                    count=1; // 重置并列的元素数量为1
                }
            }
        }
            for (int i = 0; i < n; i++) {
                printf("%dst ", p[i]->rank);
                printf("%s\n", p[i]->name);
            }
    }
    return 0;
}

中间处理并列时的思路很巧妙,请各位自行体会。

你可能感兴趣的:(学习心得,OJ,算法,数据结构,开发语言,c语言,青少年编程,学习)