C语言身份证排序(分治、快排)附详细注释

这篇博客介绍了一个C语言程序,用于对一组身份证号码进行排序。程序首先提取出生日期,然后使用快速排序算法按照日期从大到小排序。日期相同时,再依据身份证号码本身进行降序排列。博主分享了自己的学习过程,并欢迎读者提供代码改进建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之所以说它新手友好是因为我本人就是一个新手orz 学C两个半月

可能会断断续续在这里记录自己的做题日常,被卡很久的题肯定是会写过来的

也欢迎大家提出可行的代码改进意见!

题目:

有一组身份证号,请你按照生日对它们从大到小排序,如果日期相同,则按身份证号码大小排序。身份证号码为18位数字,出生日期为第7位到第14位。

输入格式

  第1行,包含1个整数n,表示有n个身份证号;
  接下来的n行,每行一个身份证号。

输出格式

  n行,按出生日期从大到小排序后的身份证号,每行一个身份证号。

输入样例

5
466272307503271156
215856472207097978
234804580401078365
404475727700034980
710351408803093165

输出样例

404475727700034980
234804580401078365
215856472207097978
710351408803093165
466272307503271156

数据范围

N<=100,000

代码(已ac):

#include<stdio.h>
long long ID[100002];
long birth[100002];

int partition(int left, int right);
//让它return l(此时l==r)

void qsort(int left, int right);
//记得先判断left<=right的时候return
//在这里面定义divide=partition(left,right,person)
//然后分别对(left,divide-1)和(divide+1,right)递归调用

void sortID(int left, int right);
//对生日相同的人根据ID从大到小排序

int main(void) {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%lld", &ID[i]);

    for (int i = 0; i < n; i++) {
        long long a = ID[i] % (long long)1e12;
        birth[i] = a / 10000;
    }//找出每个人的生日

    qsort(0, n - 1);
    //快排过后按照生日从大到小排列了

    int flag = 0;
    int left, right;
    for (int i = 0; i < n; i++) {
        //生日一样的时候flag为1
        if (birth[i] == birth[i + 1] && flag == 0) {
            flag = 1; left = i;
        }//不可以漏掉&&flag==0!

        else if (birth[i] != birth[i + 1] && flag == 1) {
            flag = 0; right = i;
            sortID(left, right);
        }
    }//对生日相同的按ID降序排列
    //此处从birth[left]到birth[right]都是相同的

    for (int i = 0; i < n; i++)
        printf("%lld\n", ID[i]);

    return 0;
}

int partition(int left, int right) {
    long std = birth[left];
    long long stdID = ID[left];
    int l = left;
    int r = right;
    /*l往右移,r往左移,最开始l处的值被std保存住了
    * 所以l处可以被赋其他的值,不用担心原数组被污染
    * 先从right开始找比std大的值(r移动,找到后退出循环,定住)
    * 把这个值birth[r]赋给l处,并且从l开始找比std小的值(l移动)
    * 注意到birth[r]的值已经被保存住了,所以可以赋值
    * 把找到的birth[l]赋给r处,继续从r处开始往左找比std大的值
    * 再把它赋给l处…… 一直到l和r相遇 */

    do {
        while ((l < r) && birth[r] < std)
            r--;
        /*while结束了说明此时的r对应birth大于等于std(为什么要有等于呢)
        * 因为把最左边定为std,要考虑如果最左边已经是最大了,r要能在0处停下来 */
        if (l < r) {
            birth[l] = birth[r];
            ID[l] = ID[r];
            l++;
        }
        //这里r处的birth被存住了,这个位置就可以尽情填别的数了

        while ((l < r) && birth[l] >= std)
            l++;
        /*while结束了说明此时l对应birth小于std
        * 这次不用考虑等于的情况了,等于也继续l++ */
        if (l < r) {
            birth[r] = birth[l];
            ID[r] = ID[l];
            r--;
        }
    } while (l != r);
    //while结束的时候l==r
    //我尝试过把这里的条件改成l<r,并且相应地把前面废话一样的if(l<r)删去
    //不过好像不能出结果 没有输出 嗯,严格控制变量只改动了这一处
    //限于水平,现在还不懂原理!如果有能讲清楚的朋友,评论区教教我吧,感谢!

    birth[l] = std;
    ID[l] = stdID;
    return l;
}

void qsort(int left, int right) {
    if (left >= right)
        return;

    int divide = partition(left, right);
    qsort(left, divide - 1);
    qsort(divide + 1, right);
    return;
}

void sortID(int left, int right) {
    for (int i = 0; i < right - left; i++) {
        for (int j = left; j < right - i; j++) {
            if (ID[j] < ID[j + 1]) {
                ID[100001] = ID[j];
                ID[j] = ID[j + 1];
                ID[j + 1] = ID[100001];
            }
        }
    }
}//这里采用冒泡排序是因为生日相同的人数据量估计不会很大,所以应该不超时

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值