排序算法虽然好用,但会破坏掉原有数组的顺序。有时候,我们并不想这样(例如在使用结构体、共用体)。
这时候,我们可以创建一个指针数组,分别指向原数组中的每个元素,对指针数组进行排序。基本思想就是在冒泡排序时定义的中间临时变量是一个指针变量,冒泡时交换的是指针,即可在不破坏原有数组的顺序下得到排序结果。若想调用排序前的直接调用原数组,若想调用排序后的数组,只需要对排序后的指针数组进行解引用即可。
以下是以最简单的排序方法——冒泡排序法实现的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;
}
下面以本题为例,请大家感受一下指针数组在结构体中的应用。
欢迎大家来参加计算机科学与工程学院ACM竞赛;既然来参加比赛,想必也知道,比赛的排名的规则吧;
首先我们按出题量排名,出题量多者,排名靠前,其次出题量一样是看出题的时间,但当时间一样时,看你的姓名的字典序排名,但名次一样;当然提交错误,会有惩罚,每提交错一次,罚时20分钟;(提示:一共有5道题,题目没有通过不罚时)
首先输出一个整数n,代表n个人;(0 < n < 100)
再有n行,每一行有一个人名,(每个人名都是由小写字母组成,且长度不超过10)在人名后面有10个数,前5个数代表出每一道题所用的时间(时间的不超过120.),后5个数代表每一道题提交错误的次数(错误次数不超过10.);当时间为0时,说明这道题没做出来;
输出排名,每一个人一行;
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
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;
}
中间处理并列时的思路很巧妙,请各位自行体会。