之所以说它新手友好是因为我本人就是一个新手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];
}
}
}
}//这里采用冒泡排序是因为生日相同的人数据量估计不会很大,所以应该不超时