HUST校园卡系统

一.问题描述

现有一批校园卡申请开户的数据,覆盖8000个以上学生的数据,数据项内容为:学号,姓名。需要在此基础上,构建校园卡管理、食堂应用和汇总分析的基本功能。具体要求包括:

①构建模拟的校园卡发卡、挂失及解挂、补卡(含多次补卡)和充值操作;

②构建模拟的校园卡在食堂各窗口消费的业务操作,包含消费、当餐超额验证消费密码等处理;

③构建模拟定期将分别按各窗口记录的消费记录进行合并汇总、查询分析等操作;

④构建各类操作日志,包含什么时间、什么人、做了什么操作、操作前的数据以及操作后被修改成的数据、操作是否成功等信息,便于回溯查询,也是用于检查当前操作是否成功和正确的依据。

⑤扩展实现:依据汇总的消费数据来分析同学们的消费习惯等规律性信息;在消费记录中,如何增加校验数据项,用来验证本条数据没有被篡改,以及数据记录没有伪造增加或正常记录没有被删除。

二.分析步骤

1.输入数据的要求

1.1 单户操作

①开户:用户输入当前时间以及学号、姓名等信息,学号要经过查重,无误后进行开户,并记录操作日志。

②销户:用户输入当前时间以及需要销户的学号,检查无误后进行销户,并记录操作日志。

③发卡:用户输入当前时间以及需要发卡的学号,检查无误后进行发卡并记录操作日志。

④挂失:用户输入当前时间以及需要挂失者的学号,系统会提示用户当前的卡号以及提示是否挂失,确认后进行挂失并记录操作日志。

⑤解挂:用户输入当前时间以及需要解挂者的学号,系统检查无误后会提示用户当前的被挂失的卡号以及提示是否解挂,确认后进行解挂并记录操作日志。

⑥补卡:用户输入当前时间以及需要补卡者的学号,系统检查后如果发现当前最新的卡号没有挂失时会要求用户挂失后再来补卡,最后系统会提示该用户以及补发获得的卡号,并记录操作日志。

⑦充值:用户输入当前时间以及需要充值的学号和充值金额,判断充值金额未超过上限后会提示用户当前卡号并进行充值,并记录操作日志,

⑧消费:用户输入当前时间、窗口号、卡号、消费金额、判断用户在当前时段的消费金额有没有累计消费超过20元,如果有则提示用户输入密码,待密码正确后才才从卡中减去消费金额并记录操作日志。

1.2 批量分析

①开户:用户输入当前时间以及学号、姓名等信息,学号要经过查重,无误后进行开户,并记录操作日志。

②销户:用户输入当前时间以及需要销户的学号,检查无误后进行销户,并记录操作日志。

③发卡:用户输入当前时间以及需要发卡的学号,检查无误后进行发卡并记录操作日志。

④挂失:用户输入当前时间以及需要挂失者的学号,系统会提示用户当前的卡号以及提示是否挂失,确认后进行挂失并记录操作日志。

⑤解挂:用户输入当前时间以及需要解挂者的学号,系统检查无误后会提示用户当前的被挂失的卡号以及提示是否解挂,确认后进行解挂并记录操作日志。

⑥补卡:用户输入当前时间以及需要补卡者的学号,系统检查后如果发现当前最新的卡号没有挂失时会要求用户挂失后再来补卡,最后系统会提示该用户以及补发获得的卡号,并记录操作日志。

⑦充值:用户输入当前时间以及需要充值的学号和充值金额,判断充值金额未超过上限后会提示用户当前卡号并进行充值,并记录操作日志,

⑧消费:用户输入当前时间、窗口号、卡号、消费金额、判断用户在当前时段的消费金额有没有累计消费超过20元,如果有则提示用户输入密码,待密码正确后才才从卡中减去消费金额并记录操作日志。

2.输出结果

2.1单个操作

①开户:根据学号的唯一性判断系统内有无当前学号,如果有则提示开户失败,如果没有则为用户开户并提示开户成功。

②销户:首先判断系统内有无用户输入的学号,并且判断当前学号是否已经销户,如果没有则提示销户成功否则提示销户失败。

③发卡:判断用户是否是第一发卡,以及发卡的学号有没有处于销户状态,如果没有则显示用户发得的卡号并提示用户发卡成功。否则提示发卡失败。

④挂失:判断用户当前卡号是否处于挂失状态,判断用户是否处于销户状态,如果都没有则将用户当前卡号挂失,并且提示挂失成功。

⑤解挂:判断用户当前卡号是否处于正常状态,判断用户当前是否处于销户状态,如果都不是则将用户当前最新卡号解挂,并提示解挂成功。

⑥补卡:判断当前用户是否销户,如果是则不能补卡。判断当前用户最新卡号是否已经处于挂失状态,如果是则提示用户补卡成功并显示最新卡号,如果不是则提示用户进行挂失操作后再来补卡。

⑦充值:判断用户当前是否销户,判断用户当前充值金额有无超过上限,如果没有则对用户充值,并提示用户充值后的余额还有多少,否则退还充值金额。

⑧消费:判断当前卡号是否处于挂失状态,判断当前卡号的余额是否支持当前消费金额,判断当前消费时间的金额有无超过20元,如果超过则提示输入密码。条件达成后提示用户余额,并提示消费成功。

2.2批量操作

用户选择批量操作后,将所有操作过程记录在操作日志中以便后续查询。并且在批量操作后用户可以选择汇总分析功能:

①查询窗口当天的消费金额与消费次数:用户输入当前时间,并输入窗口号后系统会显示当前窗口的消费金额与消费次数。

②对窗口数据按时间进行有序汇总:用户选择多路归并排序或快排后将消费记录保存在文件里,并且显示排序与写文件的时间。

③查询指定学生的余额:用户输入学号后系统将会显示该学生的余额。

④统计学生在某一时间段的消费金额:用户输入学号、起始时间段与结束时间段后,系统会显示在当前时间段内用户的总消费金额,并且显示每条消费细明。

⑤按照学号或者姓名的模糊匹配:用户按格式输入后,系统会显示匹配的姓名或学号。

⑥分析最可能一起就餐的8位同学:系统会显示8位同学的学号与卡号。

⑦检测消费文件有无被篡改的记录:如果有某一行被修改则系统会显示消费文件中哪一行被修改,如果有行数的增加与删除,系统也会提示行数的增加与删除。

三.总体设计

3.1 总体设计方案

本次实验的总体设计方案如下图:

本次实验设计预设计三个模块分别是卡片管理模块、食堂运行模块、汇总分析模块。具体模块要求如下:

①卡片管理模块:运行开户、销户、发卡、挂失、解挂、补卡、充值、批量操作等功能。批量操作是指读取相关文件并将相关信息写入内存以满足后续查询或其他操作需求。

②食堂运行模块:运行消费、窗口查询等功能。

③汇总分析模块:运行对窗口数据汇总、查询余额、模糊匹配等功能。

④其中批量操作与单个操作共用相同数据结构与存储结构,支持先批量操作后单人操作或先单人操作后批量操作。

⑤在编写模块内容时也要注意编写操作日志。

⑥各个模块之间没有操作顺序要求,但程序要对无效操作进行判断,并且各个模块之间可以循环运行,各个模块之间的子功能也可以循环运行。

四.数据结构设计

4.1 数据结构设计及相关用法

由于不同模块涉及到的数据结构略有不同,下面我将分模块介绍各个模块所利用到的数据结构及其相关用法,以表格形式展现后具体分析。

数据结构设计与相关用法如下表:

模块

包含的数据结构

具体作用

卡片管理模块

结构数组

模拟学生账户的具体信息,支持开户、销户、发卡、补卡操作。

单向链表

模拟学生发得的校园卡,支持发卡,补卡,挂失,解挂操作。

食堂应用模块

循环队列

模拟单个窗口保存的60000条消费信息,支持消费与后续分析汇总操作。

结构数组

模拟99个窗口的消费信息,支持消费与多路归并排序操作。

汇总分析模块

结构数组

用于存储按照时间排序好之后的消费记录,便于后续查询与统计操作

4.1.1 卡片管理模块

//开户读文件可以再优化 
typedef struct{			//校园卡信息,以单链表形式保存 
	char cardnum[8];
	int flag;			//flag标志着该卡的状态,0表示挂失状态,1表示激活状态 
	double cardmoney;
	double cursume79 ;//统计各个时间段的消费金额 
	double cursume1113 ;
	double cursume1719 ;
	char code[5];//密码,默认值为8888 
	struct campuscard *next;
	
}campuscard,*campuscardp;
typedef struct {
	char stunum[11];			//学号 
	campuscardp ccard;			//卡号 
	char name[9];				//姓名 
	char ddl[9];	//有效日期 
	char flag;                  //标志学号状态flag=1为正常状态,flag=0为销户状态  
					}card,*cardp;

①设计了一个包含学生姓名、学号、有效日期、指向校园卡链表头结点的指针、标志位(主要用于判断该学生是否为销户状态)的结构数组card。该数组的大小为10000。该结构数组的作用为:

1.支持开户操作,能够存储学生的姓名与学号。

2.支持销户操作,通过改变标志位来标记学生是否为销户状态。

3.支持发卡与补卡操作,有指向学生补卡信息链表的头结点的指针。

②设计了包含卡号、标志位、卡中余额、卡号密码以及7-9,11-13,17-19,这三个时间段的累计消费金额的单向链表campuscard。单向链表中每一个节点都表示该学生的一张校园卡,只有链表尾部的校园卡才是可用的,其余节点代表的校园卡都是不可用的。因此学生的最新卡号信息保存在链表的尾部。该单向链表的作用为:

1.支持发卡、补卡操作,能够保存卡号信息,最新卡号保存在链表的表尾

2.支持挂失、解挂操作,能够通过改变标志位的值达到挂失和解挂的效果。  

3.支持充值消费等操作,通过改变余额这个浮点数的大小能够完成充值和消费等操作。

4.能够判断在当前时间段的消费金额是否超过20元以及输入密码等操作。由于卡中保存了当天7-9,11-13,17-19这三个时间段的消费金额,以及密码信息,因此可以判断消费是否超额与输入密码等操作。

4.2食堂应用模块

typedef struct  {
	char date[9];
	char time[9];//记录时间 
	char XFCardNum[8];//记录卡号 
	int window;
	double pay;//支付的钱 
	int count1;//count1便于查找相关人员
	int flag; 
	int jym;
}XFmessage;

typedef struct{
	int count ; //记录队列元素个数
	int front;	//队首 
	int rear;	//队尾 
	int now;			//当前窗口消息记录的初始位置
	int flag;//便于排序 
	XFmessage xf[MAX_SIZE];
}xfwindow,*xfwindowp;

xfwindow CK[99];//便于全局使用 

①设计了一个循环队列XFmessage用来记录食堂窗口的消费信息,该队列是以一个大小为60000结构数组的形式表现出来的。数组中每一个元素包含日期、时间、卡号、窗口号、支付金额、校验码、标志位和一个count值。该循环队列的作用为:

1.保存窗口的消费记录,消费记录上限为60000条,多出的最新信息覆盖原有信息。

2.日期与时间卡号等信息便于后续排序操作,而窗口号与支付金额便于后续查询操作。校验码后续判断文件是否有被篡改等操作,标志位与count值便于后续查找最可能在一起就餐的同学。

②设计一个大小为99的结构数组xfwindow,该数组中的元素包含了一个上述的循环队列,指向队首、队尾以及当前位置的三个位置下标,一个flag值,一个count值。该结果数组的作用为:

1.记录99个窗口的消费信息。以循环队列的形式存储。

2.记录队首、队尾、当前位置的三个下标便于找到关键信息。Count值用于保存有用信息的个数,flag的作用是便于后续排序。

4.3汇总模块

typedef struct{
	char cardnum[8];
	char date[9];
	char time[9];
	int window;
	double money;
	
}tempinfo,*tempinfop;

①设计了一个结构数组tempinfo,该结构数组包含卡号、日期、时间、窗口号以及交易额。该结构数组的作用为作为:

1.便于存储食堂窗口消费信息,通过申请不同大小的结构数组可以将通过排序后的消费记录依次保存在内存中。

2.便于读取,和存储消费文件里的内容,并进行排序。

五.详细设计

5.1 总体框架算法设计

此算法是针对整个程序而言,旨在给用户提供一个良好的使用环境,并且能够满足不同模块之间、模块之内的功能选择都能有效的调用。算法设计如下:

设计一个menu用来提示用户选择不同的模块,以及模块内不同的功能。同时利用switch语句的选择功能进行判断以便进入不同的模块或函数。

4.2 卡片管理模块算法设计

①开户、销户功能算法设计:在此函数功能中需要用到结构数组S用来保存用户的学号、姓名等信息。首先提示用户输入学号与姓名,然后将输入的学号与结构数组中的学号一一比对,如果查找到相同的学号则判断此学号对应的标志位是否为0,如果是则代表该账户已经销户,提示用户是否重新开户后将标志位改为1代表开户状态,否则将输入的学号和姓名等信息保存到S数组的最新一个元素,然后提示完成开户。开户算法流程图如下:

销户流程与开户流程大体类似这里不作过多分析,其核心步骤就是改变标志位,标志位为0代表销户状态,标志位为1代表开户状态。

②发卡、补卡功能算法设计:由于卡片是以单链表形式保存的,因此发卡与补卡需要用到单链表campuscard。首先提示用户输入学号,然后在已有学号中查找是否由此学号,如果没有则提示发卡失败。否则判断该账户是否是第一次发卡,如果是则为其发卡,否则提示发卡失败。相关流程图如下:

补卡功能与发卡功能类似,区别在于补卡要先判断用户当前最新卡号是否处于挂失状态,如果不是提醒用户挂失。其次补卡所获得的卡号要保存在单链表S[i].ccard的尾部,并且要将用户其他卡号的标志位全部改为0(代表挂失状态)。

③挂失、解挂功能算法设计:对于挂失功能,首先提示用户输入需要挂失者的学号,然后从已有学号中查找。若未找到则提示未查找到用户挂失失败。找到后用一个temp指针指向保存该同学校园卡信息单链表S[i].ccard的尾部,然后将temp->flag改为0即代表挂失成功。相关流程图如下:

解挂功能与挂失功能流程类似,其核心步骤则是将temp->flag即最新卡号的标志位改为1即可。

④充值功能算法设计:对于充值功能,首先提示用户输入充值者的学号,然后在已有学号中查找是否存在有该学号,若未查找此学号则提示未查找到此学号充值失败。然后判断此学号的最新卡号是否处于挂失状态。如果是则提示用户先补卡再来充值。然后请用户输入充值金额,判断充值金额与原余额加起来是否超过1000元如果超过则提示充值失败否则在原余额上加上充值金额。

⑤批量操作功能算法设计:对于批量操作,要注意文件以及先关操作时间上的读取顺序。最先应该读取开户文件,读取时将获得的学号和姓名等信息作为参数传递给开户函数即可。对于销户、补卡、发卡等操作也应如此。对于充值和消费等操作则需要考虑到时间顺序。我们可以依据充值的时间点来确定充值和消费两种操作的进行顺序。

5.3 食堂应用模块算法设计

①消费功能算法实现:窗口消费功能要求用户先输入窗口号以及消费的卡号以及消费时间,然后判断此卡是否可用,如果不可用则提示消费失败。然后根据卡号找到学号。查找方法为将每一个学号对应的最新卡号依次与该卡号比对。如果没有找到或者卡号对应的主人以及销户则提示消费失败。然后判断此次消费时间与上一次最近的消费时间是否处于同一时间段内,如果是则cursume79(假如是7点到9点)加上消费金额,然后判断cursume79是否超过20元,是则要求输入密码然后将cursume79清零,不然不要求输入密码。另外还需要判断卡中余额是否支持本次消费,如果余额不足则提示消费失败。相关流程图见图4-7。

5.4 汇总分析模块算法设计

①对窗口数据按照时间汇总算法设计:在此要求下本人考虑了两种算法一.99路多路归并排序,二.快速排序。99路多路归并排序:由之前消费窗口的设计,每个消费窗口的消费记录都是按照时间有序排列的,可将其看成99个数组,在此基础上我们考虑多路归并排序。先将99个数组的第一个元素做比较,选出最小的那个元素,放入一个大数组,被选出来的那个数组比较位由第一位提升至第二位,依次循环直至所有元素都被放入大数组。此大数组即是按照时间有小到大排序好的数组。快速排序:先将所有消费数据都放入一个大数组,然后对此大数组按照时间的先后进行快排。快排的思想在此不作过多说明。

②模糊匹配算法设计:假设B串是用户输入的查找串,A串是原串,模糊匹配的基本思想为比较A串是否符合B串的要求。具体思路如下:

读入B串的第一个字符,当读入‘?’时将B串的开始比较位向后移动一个

字符,同时A串的开始比较位也向后移动一个字符。当读入‘*’时将B串的开始比较位向后移动一个字符,而A串的开始比较位不变。直到读入有效字符后将B串的开始比较位确定。然后确定B串的第一个有效字符串,比较A串开始比较位以后的字符串有无B串中的有效串。如果没有,则比较完成,A串不符合B串的要求。如果有则继续确定A串与B串的下一个开始比较位,寻找B串的下一个有效串比较,直到B串读完。

   ③分析最可能在一起就餐同学算法设计:思路为要求用户输入需要分析的学号。然后根据学号找到该同学曾经使用过的卡号。然后在已经排序好的消费记录数组里寻找此卡号的第一个消费时间节点。因为是已经排序好的消费记录数组,根据消费节点前后x(x不宜太大)条数据就可以找到相近时间节点的消费记录。然后寻找这些消费记录中消费窗口与目标窗口临近的y个窗口(y不宜太大)的消费记录,将这些消费记录对应的学号的count值(count值大小作为评判标准)加1。最后将此卡号的所有消费节点按此遍历,然后遍历该同学所有的消费卡号,依据count值从大到小选出8位即可分析出最可能在一起就餐的8位同学。相关流程图如下:

④消费记录校验码的设计:在我的消费记录文件中,每一条消费记录格式如下: 20210923,07001037,卡号3156996在29窗口消费6.50  

共包含5组数据,分别是日期、时间、卡号、窗口号、与消费金额。为了保证每一个数据被修改后都能检测出来,我的校验码设计规则为前4组数据相加求和然后乘以最后一项消费金额后取整。例如此条数据的校验码为:

[(20210923+7001037+3156996+29)×6.5]=197398402

检测文件时,会重新计算校验码,如果计算结果不同会提示文件在哪一行被修改过。

六.运行测试和结果分析

6.1 开发环境

本次实验的运行环境为devc++,核心代码语言为c语言。GUI界面使用中文编写,使用c语言实现。批量操作的用文件形式读取,个体操作则由用户输入。操作日志以及排序好的消费记录用文件形式保存查看。

6.2 函数声明以及调用关系

卡片管理:

void CardModel(card *infom,int* num,int* cnum)//卡片管理函数

其在运行过程中可能调用的函数有:

int KH1(card *S,int num)//开户函数
void XH1(card *S,int num)//销户函数
int FK1(card *S,int num,int cnum)//发卡函数
void GS1(card *S,int num,int cnum)//挂失函数
void GG1(card *S,int num,int cnum)//解挂函数
int BK1(card *S,int num,int cnum)//补卡函数
void CZ1(card *S,int num)//充值函数
int plcz(card *S,int num,int cnum)//批量操作函数

食堂窗口:

void CanteenModel(card *S,int num,int cnum)//食堂应用函数
void ckxf(card *S,int num ,int cnum)//窗口消费函数

汇总分析:

void HzfxModel(card *S,int num ,int cnum)//汇总分析函数  其在运行过程中可能调用的函数有:
void JCWZ()//检测文件有无被篡改函数
void FXQQ(card *S,int num)//分析经常在一起就餐同学函数
void ZHCC(card *S,int num,int cnum)//模糊匹配函数
void CKHZ()//消费信息排序函数
void CXYY(card *S,int num)//查询指定学生余额函数

宏定义:

#define MAX_money 999.99   (定义最大充值金额)

②#define MAX_SIZE 60000 (定义食堂窗口最多保存消费记录条数)

③//#define DEBUG

#ifdef DEBUG

#define msg(...) fprintf(__VA_ARGS__)

#else

#define msg(...)

#endif
七.运行结果

①开户(个人):

②销户(个人):

③发卡(个人)

④挂失、解挂(个人)

⑤补卡(个人)

⑥充值(个人)

⑦消费(个人):

当消费超过20元时,需要输入密码(默认为8888)

⑧批量操作:

首先需要在第一部里面进行批量操作读入数据,如图:

6.2 汇总分析模块运行测试分析

6.2.1对现有的数据进行排序(多路归并和快排),排序后方便之后的数据查询操作:

6.2.2查询窗口当天的消费金额与次数:

6.2.3然后进行学生账户查询余额,如图:

操作日志记录如下(部分):

6.2.3指定学生账户查询余额:

测试用例:

测试用例

学号

理论输出

实际输出

1

2020130027

0.10

0.10

2

2020331347

217.10

217.10

3

2020780761

326.45

326.45

6.2.4

学号与姓名的模糊匹配

测试用例:

测试用例

输入

1

202056*

2

刘??

3

2020??076?

输出结果如图:

分析最可能在一起就餐的同学:

测试用例

学号

1

2020130027

2

2020331347

3

2020780761

结果输出:

6.3 代码复杂度

①开户复杂度分析

开户主要程序的时间复杂度为O(n2),空间复杂度为T(1)。具体代码参见源程序。

②发卡复杂度分析

发卡主要程序的时间复杂度为O(n),空间复杂度为T(n)。具体代码参见源程序。

③充值复杂度分析

充值主要程序的时间复杂度为O(n),空间复杂度为T(1)。具体代码参见源程序。

④消费复杂度分析

消费主要程序的时间复杂度为O(n2),空间复杂度为T(1)。具体代码参见源程序。

⑤模糊匹配复杂度分析

模糊匹配主要程序的时间复杂度为O(n2),空间复杂度为T(1)。具体代码参见源程序。

⑦多路归并排序

多路归并排序真正读取文件时只考虑57路归并,且归并一次完成。其时间复杂度为O(nlogn)。空间复杂度为T(n)。

while(1){
		for(i=0;i<57;i++){
			if(D[i].flag==0){
				strcpy(tempdate,D[i].C[D[i].now].date);
				strcpy(temptime,D[i].C[D[i].now].time);
				j=i;
				break;
			}
		}
		for(i=0;i<57;i++){
		if(D[i].flag==0){
			if(((strcmp(tempdate,D[i].C[D[i].now].date))>0)){
						strcpy(tempdate,D[i].C[D[i].now].date);
						strcpy(temptime,D[i].C[D[i].now].time);
						j=i;
			}
			else if(((strcmp(temptime,D[i].C[D[i].now].time))>=0)&&((strcmp(tempdate,D[i].C[D[i].now].date))==0)){
						strcpy(tempdate,D[i].C[D[i].now].date);
						strcpy(temptime,D[i].C[D[i].now].time);
						j=i;
			}   
		}
		}
		strcpy(E[k].cardnum,D[j].C[D[j].now].cardnum);
		strcpy(E[k].date,D[j].C[D[j].now].date);
		E[k].money=D[j].C[D[j].now].money;
		strcpy(E[k].time,D[j].C[D[j].now].time);
		E[k].window=j+1;
		k++;
		D[j].now++;
		if(D[j].now==D[j].count){
			D[j].flag=1;
			s++;
		} 
		if(s==57){
			//代表全部遍历完成
			break; 
		}
	}	
	
}

快排:

void quickSort(int begin ,int end){
	if(begin<end){
		char tempdate[9];
		char temptime[9];
		char tempcard1[8];
		int tempwindow1;
		double temppay1;
		int jym1; 
		//由于此结构数组里有很多项,因此代码显得很冗长 
		char tempdate1[9];
		char temptime1[9];
		char tempcard[8];
		int tempwindow;
		double temppay;
		int jym;
		int i1,i2;
		strcpy(tempdate,tempxf[begin].date);
		strcpy(temptime,tempxf[begin].time);
		strcpy(tempcard1,tempxf[begin].XFCardNum);
		tempwindow1=tempxf[begin].window;
		temppay1=tempxf[begin].pay;
		jym1=tempxf[begin].jym;
		int i=begin;
		int j=end;
		while(i<j){
			while((i<j)&&(((strcmp(tempdate,tempxf[j].date))<0)||(((strcmp(temptime,tempxf[j].time))<=0)&&((strcmp(tempdate,tempxf[j].date))==0)))){
				j--;
			}
			//交换内容过程 
			strcpy(tempcard,tempxf[i].XFCardNum);
			tempwindow=tempxf[i].window;
			temppay=tempxf[i].pay;
			strcpy(tempdate1,tempxf[i].date);
			  strcpy(temptime1,tempxf[i].time);
			  jym=tempxf[i].jym;
			  
			  
			 strcpy(tempxf[i].date,tempxf[j].date);
			  strcpy(tempxf[i].time,tempxf[j].time);
			  strcpy(tempxf[i].XFCardNum,tempxf[j].XFCardNum);
			tempxf[i].window=tempxf[j].window;
			tempxf[i].pay=tempxf[j].pay;
			tempxf[i].jym=tempxf[j].jym;
			  
			  strcpy(tempxf[j].date,tempdate1);
			  strcpy(tempxf[j].time,temptime1);
			  strcpy(tempxf[j].XFCardNum,tempcard);
			  tempxf[j].window=tempwindow;
			  tempxf[j].pay=temppay;
			  tempxf[j].jym=jym;
			  //交换内容过程 
			  while((i<j)&&(((strcmp(tempdate,tempxf[i].date))>0)||(((strcmp(temptime,tempxf[i].time))>=0)&&((strcmp(tempdate,tempxf[i].date))==0)))){
			  		i++;
			  }
			  strcpy(tempcard,tempxf[j].XFCardNum);
				tempwindow=tempxf[j].window;
				temppay=tempxf[j].pay;
			  strcpy(tempdate1,tempxf[j].date);
			  strcpy(temptime1,tempxf[j].time);
			  jym=tempxf[j].jym;
			  
			  strcpy(tempxf[j].date,tempxf[i].date);
			  strcpy(tempxf[j].time,tempxf[i].time);
			  strcpy(tempxf[j].XFCardNum,tempxf[i].XFCardNum);
			tempxf[j].window=tempxf[i].window;
			tempxf[j].pay=tempxf[i].pay;
			tempxf[j].jym=tempxf[i].jym;
			  
			  
			  strcpy(tempxf[i].date,tempdate1);
			  strcpy(tempxf[i].time,temptime1);
			   strcpy(tempxf[i].XFCardNum,tempcard);
			  tempxf[i].window=tempwindow;
			  tempxf[i].pay=temppay;
			  tempxf[i].jym=jym;
			  
			  
		}
				strcpy(tempcard,tempxf[i].XFCardNum);
			tempwindow=tempxf[i].window;
			temppay=tempxf[i].pay;
			strcpy(tempdate1,tempxf[i].date);
			  strcpy(temptime1,tempxf[i].time);
			  jym=tempxf[i].jym;
			  
			  
				strcpy(tempxf[i].date,tempdate);
			  strcpy(tempxf[i].time,temptime);
			  strcpy(tempxf[i].XFCardNum,tempcard1);
			tempxf[i].window=tempwindow1;
				tempxf[i].pay=temppay1;
				tempxf[i].jym=jym1;
			  
			  strcpy(tempdate,tempdate1);
			  strcpy(temptime,temptime1);
			  strcpy(tempcard1,tempcard);
			tempwindow1=tempwindow;
			temppay1=temppay;
			jym1=jym;
			  
			  i1=i-1;
			  i2=i+1;
			  quickSort(begin,i1);
			  quickSort(i2,end);
	}
	else return;
	
	
}

思想:化整为零,逐个击破!

源代码见本人github仓库:beichenxin (beichenxin) / Repositories · GitHub

  • 20
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值