快速排序
在一堆数中选取一个主元,以主元为中心将这堆数分为大小两部分,对这两部分递归调用快排,最后当规模最够小的时候(小于预设的阈值CutOff)将使用简单排序(如插入排序)。
/*快速排序*/
//取主元 get pivot
long Median3(long a[], long Left, long Right)
{
int Center = (Right +Left)/2;
if (a[Left] > a[Center])
Swap(&a[Left] , &a[Center]);
if (a[Left] > a[Right])
Swap(&a[Left], &a[Right]);
if (a[Center] > a[Right])
Swap( &a[Center] , &a[Right]);
Swap(&a[Center], &a[Right - 1]);//把Povit藏到Right-1
return a[Right - 1];
}
//快速排序
void QuickSort(long a[], int Left, int Right)
{
long Pivot;//主元
int i, j;
int CutOff = 10e2;
if (CutOff <= Right - Left)
{
Pivot = Median3(a, Left, Right);
i = Left; //左边指针
j = Right - 1; //右边指针
for (;;)
{
while (a[++i] < Pivot) {}
while (a[--j] < Pivot) {}
if (i < j)
Swap(&a[i], &a[j]);
else
break;
}
Swap(&a[i], &a[Right - 1]); //Pivot 落位
QuickSort(a, Left, i - 1);
QuickSort(a, i + 1, Right);
}
else
Insertion_sort(a+Left, Right - Left+1);
}
//统一接口
void Quick_sort(long a[],int N)
{
QuickSort(a, 0, N - 1);
}
/*快速排序结束*/
快排c++背诵版:
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
int n = nums.size();
quick_sort(nums,0,n-1,n);
return nums;
}
void quick_sort(vector<int>& nums,int left,int right,int n)
{
if(left < right) //分裂到最小单位即停止
{
int pivotpos = partition(nums,left,right);
quick_sort(nums,left,pivotpos-1,n);
quick_sort(nums,pivotpos+1,right,n);
}
}
int partition(vector<int>& nums,int left,int right)
{
int povit = nums[left]; //区间最左端为主元
while(left < right)
{
while(left < right && nums[right]>= povit)
right--;
nums[left] = nums[right];//小数换到左边去
while(left < right && nums[left] <= povit)
left++;
nums[right] = nums[left];//大数换到右边去
}
nums[left] = povit;//主元落位
return left;
}
};
快速排序效率:

基数排序:
桶排序的升级版,即是将数据按某种分类丢到M个桶里面,常用次位优先原则(例如对0~999范围内的N个数排序,先按照个位数的0到9分类将数据丢入相应 ”桶“ 中。然后进入第二轮分类,依次按照桶的顺序和桶内部顺序将数据按十位数的0到9的分类。随后第三轮分类同理。最后依次输出,即完成了排序)
特点:将数据切割成若干个分类进行比较,在类似对百万级的电话号码进行排序的问题上,使用基数排序效率较高。
次位优先模板:
/* 基数排序 - 次位优先 */
/* 假设元素最多有MaxDigit个关键字,基数全是同样的Radix */
#define MaxDigit 4
#define Radix 10
/* 桶元素结点 */
typedef struct Node *PtrToNode;
struct Node {
int key;
PtrToNode next;
};
/* 桶头结点 */
struct HeadNode {
PtrToNode head, tail;
};
typedef struct HeadNode Bucket[Radix];
int GetDigit ( int X, int D )
{ /* 默认次位D=1, 主位D<=MaxDigit */
int d, i;
for (i=1; i<=D; i++) {
d = X % Radix;
X /= Radix;
}
return d;
}
void LSDRadixSort( ElementType A[], int N )
{ /* 基数排序 - 次位优先 */
int D, Di, i;
Bucket B;
PtrToNode tmp, p, List = NULL;
for (i=0; i<Radix; i++) /* 初始化每个桶为空链表 */
B[i].head = B[i].tail = NULL;
for (i=0; i<N; i++) { /* 将原始序列逆序存入初始链表List */
tmp = (PtrToNode)malloc(sizeof(struct Node));
tmp->key = A[i];
tmp->next = List;
List = tmp;
}
/* 下面开始排序 */
for (D=1; D<=MaxDigit; D++) { /* 对数据的每一位循环处理 */
/* 下面是分配的过程 */
p = List;
while (p) {
Di = GetDigit(p->key, D); /* 获得当前元素的当前位数字 */
/* 从List中摘除 */
tmp = p; p = p->next;
/* 插入B[Di]号桶尾 */
tmp->next = NULL;
if (B[Di].head == NULL)
B[Di].head = B[Di].tail = tmp;
else {
B[Di].tail->next = tmp;
B[Di].tail = tmp;
}
}
/* 下面是收集的过程 */
List = NULL;
for (Di=Radix-1; Di>=0; Di--) { /* 将每个桶的元素顺序收集入List */
if (B[Di].head) { /* 如果桶不为空 */
/* 整桶插入List表头 */
B[Di].tail->next = List;
List = B[Di].head;
B[Di].head = B[Di].tail = NULL; /* 清空桶 */
}
}
}
/* 将List倒入A[]并释放空间 */
for (i=0; i<N; i++) {
tmp = List;
List = List->next;
A[i] = tmp->key;
free(tmp);
}
}
主位优先模板:
/* 基数排序 - 主位优先 */
/* 假设元素最多有MaxDigit个关键字,基数全是同样的Radix */
#define MaxDigit 4
#define Radix 10
/* 桶元素结点 */
typedef struct Node *PtrToNode;
struct Node{
int key;
PtrToNode next;
};
/* 桶头结点 */
struct HeadNode {
PtrToNode head, tail;
};
typedef struct HeadNode Bucket[Radix];
int GetDigit ( int X, int D )
{ /* 默认次位D=1, 主位D<=MaxDigit */
int d, i;
for (i=1; i<=D; i++) {
d = X%Radix;
X /= Radix;
}
return d;
}
void MSD( ElementType A[], int L, int R, int D )
{ /* 核心递归函数: 对A[L]...A[R]的第D位数进行排序 */
int Di, i, j;
Bucket B;
PtrToNode tmp, p, List = NULL;
if (D==0) return; /* 递归终止条件 */
for (i=0; i<Radix; i++) /* 初始化每个桶为空链表 */
B[i].head = B[i].tail = NULL;
for (i=L; i<=R; i++) { /* 将原始序列逆序存入初始链表List */
tmp = (PtrToNode)malloc(sizeof(struct Node));
tmp->key = A[i];
tmp->next = List;
List = tmp;
}
/* 下面是分配的过程 */
p = List;
while (p) {
Di = GetDigit(p->key, D); /* 获得当前元素的当前位数字 */
/* 从List中摘除 */
tmp = p; p = p->next;
/* 插入B[Di]号桶 */
if (B[Di].head == NULL) B[Di].tail = tmp;
tmp->next = B[Di].head;
B[Di].head = tmp;
}
/* 下面是收集的过程 */
i = j = L; /* i, j记录当前要处理的A[]的左右端下标 */
for (Di=0; Di<Radix; Di++) { /* 对于每个桶 */
if (B[Di].head) { /* 将非空的桶整桶倒入A[], 递归排序 */
p = B[Di].head;
while (p) {
tmp = p;
p = p->next;
A[j++] = tmp->key;
free(tmp);
}
/* 递归对该桶数据排序, 位数减1 */
MSD(A, i, j-1, D-1);
i = j; /* 为下一个桶对应的A[]左端 */
}
}
}
void MSDRadixSort( ElementType A[], int N )
{ /* 统一接口 */
MSD(A, 0, N-1, MaxDigit);
}
例题:10-排序5 PAT Judge (25分)
The ranklist of PAT is generated from the status list, which shows the scores of the submissions. This time you are supposed to generate the ranklist for PAT.
Input Specification:
Each input file contains one test case. For each case, the first line contains 3 positive integers, N (≤10e4
), the total number of users, K (≤5), the total number of problems, and M (≤10e5 ), the total number of submissions. It is then assumed that the user id’s are 5-digit numbers from 00001 to N, and the problem id’s are from 1 to K. The next line contains K positive integers p[i] (i=1, …, K), where p[i] corresponds to the full mark of the i-th problem. Then M lines follow, each gives the information of a submission in the following format:
user_id problem_id partial_score_obtained
where partial_score_obtained is either −1 if the submission cannot even pass the compiler, or is an integer in the range [0, p[problem_id]]. All the numbers in a line are separated by a space.
Output Specification:
For each test case, you are supposed to output the ranklist in the following format:
rank user_id total_score s[1] ... s[K]
where rank is calculated according to the total_score, and all the users with the same total_score obtain the same rank; and s[i] is the partial score obtained for the i-th problem. If a user has never submitted a solution for a problem, then “-” must be printed at the corresponding position. If a user has submitted several solutions to solve one problem, then the highest score will be counted.
The ranklist must be printed in non-decreasing order of the ranks. For those who have the same rank, users must be sorted in nonincreasing order according to the number of perfectly solved problems. And if there is still a tie, then they must be printed in increasing order of their id’s. For those who has never submitted any solution that can pass the compiler, or has never submitted any solution, they must NOT be shown on the ranklist. It is guaranteed that at least one user can be shown on the ranklist.
Sample Input:
7 4 20
20 25 25 30
00002 2 12
00007 4 17
00005 1 19
00007 2 25
00005 1 20
00002 2 2
00005 1 15
00001 1 18
00004 3 25
00002 2 25
00005 3 22
00006 4 -1
00001 2 18
00002 1 20
00004 1 15
00002 4 18
00001 3 4
00001 4 2
00005 2 -1
00004 2 0
Sample Output:
1 00002 63 20 25 - 18
2 00005 42 20 0 22 -
2 00007 42 - 25 - 17
2 00001 42 18 18 4 2
5 00004 40 15 0 25 -
思路:
一开始整合数据,将某人的AK题目数量,某人的总得分,还有这个人的各个题目的具体得分情况数组*score全部塞到一个机构体里面,将数据按照题目中的规则要求完成输入。随后用STL的sort排序(需要自己写cmp函数),最后输出。
需要注意的是:
1.sort()的第三个参数–cmp函数的写法,cmp是个bool函数,需要排在前面的元素就返回一个true。
2.注意结构体的写法那里,为了表示 指向结构体指针的数组,只需要 结构体 数组名[大小]* 就可以了,不需要在那搞 双重指针(虽然其实是一个意思,但是写起来晕乎乎的,有时候搞着搞着搞出把双重指针装数组变成三重指针了 = = )。
3.遍历所有人那里,flag的值要写在if的外面。这其实是一种常规的写法,因为if很可能不执行,这样如果有一个不进if里面的用例,就会导致这个用例的flag用的是前面那个进if的值,会导致程序出错。 总之,这种flag监控值的每轮初始化,不要进if,最好每次循环立刻做。
4.要表示某种,第一次执行的时候成立,后来的(相等情况)就不成立的情况(比如重复提交满分成绩)。可以参考本程序最后那个Tmp的设置,先设置一个超越常规的数字,然后第一次执行的时候必然会成立,然后之后的等于情况就不进if了。有点哨兵的感觉?
#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int MaxUsersNumber = 10e4;//最大人数 1~10e4
const int MaxProblems = 5;//最多12345,物种题型
int Point[MaxProblems] = { 0 };//12345个问题
struct UserNode {
int *Score;//各题得分情况
int KilledNumbers;//解决过的问题数量
int TotalScore;//总分
};
UserNode* ranklist[MaxUsersNumber];//人头数组,里面直接装结构体指针
bool cmp(int a , int b)
{
if (ranklist[a]->TotalScore > ranklist[b]->TotalScore)
return true;
else if (ranklist[a]->TotalScore == ranklist[b]->TotalScore)
{
if (ranklist[a]->KilledNumbers > ranklist[b]->KilledNumbers)
return true;
else if (ranklist[a]->KilledNumbers == ranklist[b]->KilledNumbers)
if (a < b) return true;
}
return false;
}
int main()
{
int N, K, M;
cin >> N >> K >> M;
for (int i = 0; i < K; i++)
cin >> Point[i]; //记录下各个题目的得分
for (int i = 1; i <= N; i++)
ranklist[i] = NULL;
vector<int> vec;//供打印的容器装入有过得分的
int flag;//是否提交过答案
int ID;
int SubID, SubProblem, SubScore;
for (int i = 0; i < M; i++)//提交次数循环
{
cin >> SubID >> SubProblem >> SubScore;
if (!ranklist[SubID])//若是某人的首次提交
{
ranklist[SubID] = new UserNode;
ranklist[SubID]->Score = new int[K]; //开辟每题的得分数组
for (int j = 0; j < K; j++)//初始化得分数组
ranklist[SubID]->Score[j] = -2;//没提交标记为-2
ranklist[SubID]->TotalScore = 0;
ranklist[SubID]->KilledNumbers = 0;//完成初始化
}
if (ranklist[SubID]->Score[SubProblem - 1] < SubScore)//若非首次提交,且新提交的分数更大
ranklist[SubID]->Score[SubProblem - 1] = SubScore; //更新该题得分(如果没通过则变成-1,对应最后的0分)
}
for (ID = 1; ID <= N; ID++)//遍历所有人
{
flag = 0;//初始化成所有题目都没通过
if (ranklist[ID])//如果此人提交过
{
for (int j = 0; j < K; j++)
{
if (ranklist[ID]->Score[j] >= 0) //若此题提交过
{
flag = 1;//这个人有题目提交了
ranklist[ID]->TotalScore += ranklist[ID]->Score[j];
}
if (ranklist[ID]->Score[j] == Point[j])//这题拿了满分
ranklist[ID]->KilledNumbers++;
}//计算完这个人的各题得分和总分了
//if (flag == 1) //有可能有人压根就没提交过,所以要放在if内层,不然没提交的人会用前一个ID的flag
//vec.push_back(ID);//若有过得分,则可以加入排序了
}
if (flag == 1)
vec.push_back(ID);//若有过得分,则可以加入排序了
}
sort(vec.begin(), vec.end(), cmp);
/*cout << "***********\n";
cout << "1: " << ranklist[1]->KilledNumbers << " 5: " <<
ranklist[5]->KilledNumbers << " 7: " << ranklist[7]->KilledNumbers;
*/
string IDstr;
int FinalRank;//最后的rank排名
int Tmp = 1000;//用来重复提交,后面的提交成绩没有前面好的情况
//等于1000(大于100就行)是让第一轮判断可以跑起来
for (int i = 0; i < vec.size(); i++)
{
ID = vec[i];//此时,vec里面装的就是排序后的ID顺序
if (ranklist[ID]->TotalScore < Tmp) {
FinalRank = i + 1;//vec是从0开始的,排序是从1开始的
Tmp = ranklist[ID]->TotalScore;//记录最好排名(下次跑if判断就是等于了,rank不会动)
}
//FinalRank = i + 1;
IDstr = to_string(ID);
while (IDstr.size() < 5)
IDstr = "0" + IDstr;
cout << FinalRank<<" " << IDstr<<" "
<< ranklist[ID]->TotalScore;//输出rank,id和总得分
for (int j = 0; j < K; j++)
{
if (ranklist[ID]->Score[j] == -2)//若这个人的某题没有提交过
cout << " -";
else if (ranklist[ID]->Score[j] == -1)//若这个人的某题提交过但是没通过
cout << " 0";
else
cout <<" "<<ranklist[ID]->Score[j];
}
cout << "\n";
}
return 0;
}
其中tmp那一块看的不是太懂,主要是逻辑上我认为输入的时候不可能产生重复的ID,也就不会有一个ID对应多个rank的情况。但事实上,如果不写会有如下报错:

加上rank保证ID的唯一性后就AC了。

本文介绍了PAT考试中的排名生成问题,该问题涉及到排序算法的应用。首先,文章概述了快速排序的基本原理和C++实现,接着解释了基数排序的概念,它是桶排序的一种优化。在给定的样例输入和输出中,展示了如何根据得分和提交记录生成排名。解决方案包括将数据整理成结构体,并利用STL的sort函数进行排序,同时注意排序函数的编写和结构体数组的声明方式。此外,文章强调了在处理过程中初始化标志变量、处理重复满分成绩等问题的注意事项。
734

被折叠的 条评论
为什么被折叠?



