C语言数据结构:4/19 & 4/20

本文介绍了如何用C语言实现链式队列的创建、插入、删除和显示功能,以及二叉树的中序遍历和后序遍历。包括`create_link_from`、`Enter_from`等函数和`create_tree`、`pri_show`等二叉树操作函数。

1.思维导图

2.链式队列代码

main.c

#include "link_from.h"
int main(){
	point_p P=create_link_from(10);
	Enter_from(P,11);
	Enter_from(P,12);
	Enter_from(P,13);
	Enter_from(P,14);
	Enter_from(P,15);
	Enter_from(P,16);

	show_from(P);


	Pop_from(P);
	Pop_from(P);
	Pop_from(P);
	show_from(P);
	return 0;
}

link_from.c

#include "link_from.h"
point_p create_link_from(datatype data){
	point_p P=(point_p)malloc(sizeof(point));
	if(P==NULL){
		printf("空间申请失败\n");
		return NULL;
	}
	node_p F=(node_p)malloc(sizeof(node));
	if(F==NULL){
		printf("空间申请失败\n");
		return NULL;
	}
	P->front=F;
	P->rear=F;
	F->data=data;
	F->next=NULL;
	return P;
}
void Enter_from(point_p P,datatype data){
	if(P==NULL){
		printf("空间申请失败\n");
		return;
	}
	node_p new=NULL;
	new=(node_p)malloc(sizeof(node));
	

	P->rear->next=new;
	P->rear=new;
	new->data=data;
	new->next=NULL;	
}
int empty_from(point_p P){
	if(P==NULL){
		printf("入参为空\n");
		return -1;
	}
	return P->front==P->rear?1:0;
}
void show_from(point_p P){
	if(P==NULL){
		printf("入参为空\n");
		return;
	}
	node_p p=P->front;
	while(p!=P->rear){
		printf("%-4d",p->data);
		p=p->next;
	}
	printf("%-4d",p->data);
	putchar(10);
}
void Pop_from(point_p P){
	if(P==NULL){
		printf("空间申请失败\n");
		return;
	}
	if(empty_from(P)){
		printf("队列为空,无法输出\n");
		return;
	}	
	node_p del=P->front;
	P->front=P->front->next;
	free(del);
	/*node_p p=P->front;
	while(p->next!=P->rear){
		p=p->next;
	}
	node_p del=P->rear;
	P->rear=p;
	p->next=NULL;
	free(del);*/
}

link_from.h

#ifndef __LINK_FROM_H__
#define __LINK_FROM_H__
#include <stdio.h>
#include <stdlib.h>
typedef int datatype;
typedef struct node{
	datatype data;
	struct node* next;
}node,*node_p;

typedef struct point{
	struct node* front;
	struct node* rear;
}point,*point_p;
point_p create_link_from(datatype data);
void Enter_from(point_p P,datatype data);
void Pop_from(point_p P);
void show_from(point_p P);



#endif

运行演示:

3.二叉树中序遍历&后序遍历

3.1中序遍历
 
void med_show(node_p T){
	if(T==NULL){
		return;
	}
	med_show(T->lchild);
	printf("%c",T->data);
	med_show(T->rchild);	
}
3.2后序遍历
 
void rig_show(node_p T){
	if(T==NULL){
		return;
	}
	rig_show(T->lchild);
	rig_show(T->rchild);
	printf("%c",T->data);

}
3.3代码总结

tree.c

#include "tree.h"
node_p create_tree(){
	char input='\0';
	scanf(" %c",&input);
	if(input=='#'){
		return NULL;
	}
	node_p new=create_node(input);
	new->lchild=create_tree();
	new->rchild=create_tree();
	return new;
}
node_p create_node(datatype input){
	node_p new=(node_p)malloc(sizeof(node));
	if(new==NULL){
		printf("空间申请失败\n");
		return NULL;
	}
	new->data=input;
	return new;
}
void pri_show(node_p T){
	if(T==NULL){
		return;
	}
	printf("%c",T->data);
	pri_show(T->lchild);
	pri_show(T->rchild);
}
void med_show(node_p T){
	if(T==NULL){
		return;
	}
	med_show(T->lchild);
	printf("%c",T->data);
	med_show(T->rchild);	
}
void rig_show(node_p T){
	if(T==NULL){
		return;
	}
	rig_show(T->lchild);
	rig_show(T->rchild);
	printf("%c",T->data);

}

tree.h

#ifndef __TREE_H__
#define __TREE_H__
#include <stdio.h>
#include <stdlib.h>
typedef char datatype;
typedef struct node{
	char data;
	struct node* lchild;
	struct node* rchild;
}node,*node_p;
node_p create_tree();
node_p create_node(datatype input);
void pri_show(node_p T);
void rig_show(node_p T);
void med_show(node_p T);


#endif

运行演示:

4.画二叉树:先序:FCADBEHGM & 中序:ACBDFHEMG

&lt;think&gt;我们面临的任务是:实现一个程序,管理App的注册(根据时间段和优先级),并在指定时间点查询使用哪个App。 要求: 1. 输入分为三部分: - 第一行:整数N(&lt;=100),表示注册的App数量 - 接下来N行:每行四个数据,以空格分隔:App名称、优先级(1-5)、起始时间、结束时间(时间格式HH:MM) - 最后一行:一个时间点(HH:MM),查询该时间点使用的App 2. 规则: - 注册时间段包含起始时间,不包含结束时间。例如:注册时段09:00-10:00,那么09:00(包含)到10:00(不包含)属于该时段。 - 一个时间段只能被一个App占用。当发生冲突时,优先级高的App会覆盖优先级低的App(即注销低优先级的时段)。 - 如果两个App优先级相同,则后注册的不能覆盖先注册的(即先注册的有效,后注册的冲突部分被忽略)。 - 如果注册的起始时间&gt;=结束时间,则注册不上(忽略该条注册)。 3. 输出: - 在指定时间点,如果有注册的App,则输出App名称;否则输出&quot;NA&quot;。 设计思路: 由于一天24小时,我们可以将时间转换为分钟(0~1440分钟),这样便于处理时间段。 步骤: 1. 读取N。 2. 定义结构体来存储每个App的注册信息(包括名称、优先级、起始分钟数、结束分钟数)。 3. 读取N行数据,对每一行: - 将时间字符串转换为分钟数(例如&quot;09:00&quot; -&gt; 540分钟)。 - 检查起始时间是否小于结束时间,如果不是,则跳过该条注册。 4. 我们需要维护一个时间表(数组)来表示每个分钟点被哪个App占用。由于时间点只有1440个,我们可以创建一个长度为1440的数组(每个元素代表该分钟点被哪个App占用,初始为-1表示没有App)。 但是注意:规则中一个时段只能被一个App占用,而且冲突处理是基于优先级的。然而,同一个App可以在多个时段注册,且不同App的时段可能重叠。 5. 如何处理冲突? 我们可以按照优先级和注册顺序来处理。但注意:规则是&ldquo;高优先级覆盖低优先级,同优先级则后注册的不能覆盖先注册的&rdquo;。因此,我们考虑按顺序处理每条注册请求,但优先级高的应该先处理?不,因为后注册的高优先级需要覆盖之前注册的低优先级。 实际上,我们需要按照优先级从高到低的顺序处理注册请求?但是注册顺序也有要求:同优先级时,先注册的有效,后注册的冲突部分无效(即不能覆盖先注册的同优先级时段)。然而,如果后注册的优先级高,则可以覆盖之前注册的低优先级时段。 因此,我们可以先按优先级从高到低排序,如果优先级相同,则按注册顺序的先后(先注册的排在前面)?但是注意:规则是&ldquo;后添加的App不能注册(当优先级相同时)&rdquo;,也就是说,在优先级相同的情况下,先注册的会阻止后注册的(冲突部分)。所以,我们应当先处理先注册的?但是高优先级又需要覆盖低优先级。 我们换个思路:我们维护一个时间表,初始所有时间点都没有App。然后我们按顺序(从先注册到后注册)处理每条注册请求?不行,因为后注册的高优先级需要覆盖之前注册的低优先级,所以我们应该先处理高优先级的注册请求,再处理低优先级的?但是同优先级时,先处理先注册的,后处理的后注册的(因为后注册的不能覆盖先注册的,所以如果先处理了后注册的,再处理先注册的,就会覆盖掉后注册的,而规则是后注册的不能注册(冲突部分))。 实际上,我们可以这样: - 将所有有效的注册请求(起始时间&lt;结束时间)保存到一个数组。 - 然后按照优先级从高到低排序,如果优先级相同,则按照注册顺序的逆序(即先注册的排在后面)?这样不行。 另一种方法:我们按优先级从高到低排序,同优先级按注册顺序从先到后排序?然后按这个顺序处理。但是规则是:高优先级可以覆盖低优先级,同优先级时后注册的不能覆盖先注册的(即先注册的保留,后注册的冲突部分被丢弃)。所以,如果我们先处理高优先级的,再处理低优先级的,那么低优先级在注册时,如果时间点已经被高优先级占用,则不能占用(这符合规则)。但是同优先级之间呢?如果我们按注册顺序先后来处理(先注册的先处理),那么后注册的如果和先注册的冲突,后注册的冲突部分就会被丢弃(因为先注册的已经占用了)。所以,同优先级应该先处理先注册的。 因此,排序规则: - 首先按优先级降序(优先级高的在前) - 其次按注册顺序升序(先注册的在前) 然后,我们按这个顺序依次将每个App的注册时间段写入时间表,写入规则:对于该时间段内的每个分钟点,如果当前时间点还没有被占用(或者被优先级更低的占用,但因为我们按优先级从高到低,所以之前写入的优先级一定不低于当前?所以实际上,我们按优先级从高到低写入,那么后写入的优先级一定不会高于先写入的?不对,同优先级时,先写入的(先注册的)先写入,后写入的(后注册的)同优先级,那么后写入的只能写入没有被先注册的同优先级App占用的时间段。 但是,我们这样写:在写入一个时间段时,我们只考虑这个时间段内还没有被占用的时间点(即只覆盖那些空闲的或者被优先级更低的App占用的时间点?)。但是,我们按优先级从高到低写入,那么当我们写入一个时间段时,如果这个时间段内有些时间点已经被更高优先级的占用了(因为我们是按优先级从高到低,所以之前写入的优先级更高或相同,但相同优先级时,先写入的已经写入了),那么当前这个时间段就只能写入那些没有被占用的时间点?这不符合规则:规则是高优先级覆盖低优先级,但同优先级时,后注册的不能覆盖先注册的。所以,在写入时: - 如果当前时间段内某个时间点已经被占用,那么有两种情况: a) 被更高优先级的占用:那么当前时间段不能覆盖(因为优先级不如它高)-&gt; 但是,我们当前注册的优先级如果比之前占用的优先级高,那么就可以覆盖?不对,我们排序是优先级高的先处理,所以当前处理的优先级一定不会高于之前已经处理过的?因为我们是降序排列的,所以当前处理的优先级&lt;=之前处理过的优先级。 - 所以,当我们处理一个时间段时,这个时间段内的时间点可能已经被更高优先级或相同优先级的占用了。对于相同优先级的情况,如果之前已经有一个同优先级的占用了,那么当前这个时间段(后注册的)就不能覆盖(所以不能写入)。因此,在写入时,对于当前时间段的每个时间点,我们只写入那些没有被占用的时间点(因为之前写入的优先级都&gt;=当前,所以当前不能覆盖它们)。 但是,这样会导致一个问题:高优先级先写入,低优先级后写入,低优先级不能覆盖高优先级(正确),同优先级先写入的先写入,后写入的不能覆盖(正确)。但是,这样后写入的同优先级App只能写入那些没有被先写入的同优先级App占用的时间点,这符合规则。 所以,我们按优先级降序、注册顺序升序(即先注册的先处理)排序后,然后按顺序写入时间表:对于每个时间点,如果当前时间点还没有被占用,则写入当前App名称;否则,跳过(因为已经被更高优先级或同优先级但先注册的占用了)。 但是,注意:一个App可以在多个时段注册,所以同一个App可能有多条注册信息。这些注册信息是独立的,按规则处理。 6. 具体步骤: a) 读取N。 b) 定义一个结构体数组来存储注册信息(包括:名称、优先级、开始分钟、结束分钟)。 c) 读取N行,对每一行: - 拆分字符串,得到四个部分。 - 将开始时间和结束时间转换为分钟数。 - 如果开始分钟&gt;=结束分钟,跳过。 - 否则,保存这条注册信息(同时记录它的注册顺序,即读取的顺序,从0开始)。 d) 对注册信息数组进行排序: - 优先级高的在前(优先级数值大的在前) - 优先级相同,则注册顺序在前的在前(即注册顺序值小的在前) e) 初始化一个长度为1440的数组`time_table`,每个元素初始为-1(表示没有App)或者可以用一个特殊值表示未占用。但我们这里可以存储App的名称吗?不,我们存储的是App的索引?或者直接存储App名称?但是一个时间点只能有一个App,所以我们可以存储App名称(字符串)?但是这样在写入时,我们需要存储字符串,比较麻烦。我们可以存储注册信息的索引?但是最后查询时,我们只需要知道名称。 实际上,我们可以用一个字符串指针数组,长度为1440,初始化为NULL。然后,对于排序后的每个注册信息,我们遍历该时间段内的每一个分钟点(注意:时间段包含起始分钟,不包含结束分钟),如果该分钟点当前为NULL,则将其指向当前App的名称(字符串)。但是注意:同一个App的多个时段是独立的,所以每个时段都要处理。 但是,这样会有一个问题:同一个App的多个时段,如果它们不重叠(或者重叠但优先级相同且先注册的已经占用了,后注册的时段可能部分占用),那么它们可以分别占用不同的时间点。 f) 按排序后的顺序处理每条注册信息: for 每条注册信息(从排序后的数组第一个到最后): 从开始分钟到结束分钟-1(因为不包含结束分钟)的每个分钟点: 如果当前分钟点对应的`time_table`为NULL,则将其设置为当前App的名称(字符串指针)。 否则,跳过(因为已经被更高优先级或同优先级先注册的占用了)。 g) 读取查询时间点,将其转换为分钟数。 h) 检查该分钟数对应的`time_table`: - 如果为NULL,输出&quot;NA&quot; - 否则,输出对应的字符串。 7. 注意:我们存储的是字符串指针,所以我们需要在结构体中存储App名称(字符串),并且在注册信息数组中保存这些字符串。在写入时间表时,我们直接使用该字符串指针。 8. 内存:注册信息数组最多100条,时间表数组1440个指针,可以接受。 9. 但是,同一个App的多个时段是独立的,所以我们在处理时,每个时段都独立处理(按照优先级和注册顺序与其他App的时段一起排序)。 10. 例子验证: 假设有两条注册: App1 优先级5 09:00 10:00 App2 优先级4 09:30 10:30 排序:App1在前,App2在后。 处理App1:时间段09:00-10:00(分钟数:540到600-1,即540到599),将540到599设置为App1。 处理App2:时间段09:30-10:30(分钟数570到630-1,即570到629) 其中570到599已经被App1占用(优先级5&gt;4,所以不能覆盖),所以只能设置600到629(即10:00到10:29)为App2。 查询09:30(570分钟):属于App1(因为App1从540到599,所以570在App1时间段内)-&gt; 输出App1。 查询10:00(600分钟):属于App2 -&gt; 输出App2。 符合预期。 再考虑同优先级: App1 优先级5 09:00 10:00 App3 优先级5 09:30 10:30 (后注册的,同优先级) 排序:优先级相同,按注册顺序(假设App1先注册,所以App1在前,App3在后) 处理App1:设置540-599为App1。 处理App3:时间段570-629,但是570-599已经被App1(同优先级)占用,所以只能设置600-629为App3。 查询09:45(585分钟)-&gt; App1 查询10:15(615分钟)-&gt; App3 但是,如果注册顺序反过来(先注册App3,再注册App1)? 那么排序后:App3(先注册)在前,App1(后注册)在后。 处理App3:设置570-629为App3。 处理App1:时间段540-599,其中540-569没有被占用,设置为App1;而570-599已经被App3占用(同优先级,后注册的App1不能覆盖先注册的App3),所以570-599还是App3。 查询09:45(585分钟)-&gt; App3(因为App3占用了570-629,包括585) 所以,同优先级时,先注册的会占用,后注册的不能覆盖。 11. 因此,算法正确。 12. 代码实现(C语言): - 步骤: 1. 定义结构体:AppReg,包含:char name[101](假设名称不超过100字符)、int priority、int start_min、int end_min、int order(记录注册顺序,即输入的顺序)。 2. 读取N,然后循环N次读取。 3. 将时间字符串转换为分钟:例如&quot;09:00&quot; -&gt; 9*60+0=540。 4. 过滤掉开始分钟&gt;=结束分钟的注册。 5. 记录有效的注册信息,并设置order(按读取顺序,从0递增)。 6. 对有效的注册信息数组(大小为count)进行排序: qsort(regs, count, sizeof(AppReg), compare); compare函数:先按优先级降序(priority大的在前),若相同,则按order升序(小的在前)。 7. 初始化时间表:char *time_table[1440]; // 1440个指针,指向字符串 for (int i=0; i&lt;1440; i++) time_table[i] = NULL; 8. 遍历排序后的注册信息数组: for (int i=0; i&lt;count; i++) { int start = regs[i].start_min; int end = regs[i].end_min; // 注意:不包含end_min for (int min=start; min&lt;end; min++) { if (min &lt;0 || min&gt;=1440) continue; // 确保在0~1439范围内 if (time_table[min] == NULL) { // 还没有被占用 time_table[min] = regs[i].name; // 注意:这里我们存储的是结构体中的name,它是字符数组,所以每个注册信息有自己的name数组,不会冲突。 } } } 9. 读取查询时间,转换为分钟数min_query。 10. 如果min_query在0~1439内,且time_table[min_query]!=NULL,则输出time_table[min_query];否则输出&quot;NA&quot;。 13. 注意:同一个App的多个时段会被当作多个独立的注册信息,分别处理。 14. 边界:时间点00:00对应0分钟,23:59对应1439分钟。 15. 时间转换函数:可以写一个函数,将字符串&quot;HH:MM&quot;转换为分钟。 16. 输入的时间字符串是两位两位的,所以可以直接解析。 17. 代码示例: #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;string.h&gt; typedef struct { char name[101]; int priority; int start_min; int end_min; int order; // 记录注册顺序 } AppReg; // 将时间字符串&quot;HH:MM&quot;转换为分钟数 int time_to_minutes(char *time_str) { char hour_str[3], min_str[3]; strncpy(hour_str, time_str, 2); hour_str[2] = &#39;\0&#39;; strncpy(min_str, time_str+3, 2); min_str[2] = &#39;\0&#39;; int hour = atoi(hour_str); int minute = atoi(min_str); return hour * 60 + minute; } // 比较函数:优先级降序,相同则按order升序 int compare(const void *a, const void *b) { AppReg *reg1 = (AppReg *)a; AppReg *reg2 = (AppReg *)b; if (reg1-&gt;priority != reg2-&gt;priority) { return reg2-&gt;priority - reg1-&gt;priority; // 降序 } return reg1-&gt;order - reg2-&gt;order; // 升序 } int main() { int n; scanf(&quot;%d&quot;, &amp;n); AppReg regs[100]; // 最多100个 int count = 0; // 有效注册数 for (int i = 0; i &lt; n; i++) { char name[101]; int priority; char start_time[6], end_time[6]; scanf(&quot;%s %d %s %s&quot;, name, &amp;priority, start_time, end_time); // 转换为分钟 int start_min = time_to_minutes(start_time); int end_min = time_to_minutes(end_time); // 检查时间有效性 if (start_min &gt;= end_min) { continue; // 无效注册 } // 复制到结构体 strcpy(regs[count].name, name); regs[count].priority = priority; regs[count].start_min = start_min; regs[count].end_min = end_min; regs[count].order = count; // 当前count就是注册顺序(按输入顺序,先输入的order值小) count++; } // 排序 qsort(regs, count, sizeof(AppReg), compare); // 初始化时间表:1440分钟,每个分钟点用指针指向App名称,初始为NULL char *time_table[1440] = {NULL}; // 初始化为NULL // 处理每个注册信息 for (int i = 0; i &lt; count; i++) { int start = regs[i].start_min; int end = regs[i].end_min; for (int min = start; min &lt; end; min++) { // 确保分钟在0~1439范围内 if (min &gt;= 0 &amp;&amp; min &lt; 1440) { // 如果该分钟还没有被占用,则占用 if (time_table[min] == NULL) { time_table[min] = regs[i].name; // 指向当前注册信息的name } } } } // 读取查询时间 char query_time[6]; scanf(&quot;%s&quot;, query_time); int query_min = time_to_minutes(query_time); // 查询 if (query_min &gt;=0 &amp;&amp; query_min &lt;1440 &amp;&amp; time_table[query_min] != NULL) { printf(&quot;%s\n&quot;, time_table[query_min]); } else { printf(&quot;NA\n&quot;); } return 0; } 18. 测试用例: 输入: 2 App1 5 09:00 10:00 App2 4 09:30 10:30 09:30 输出:App1 输入: 2 App1 5 09:00 10:00 App3 5 09:30 10:30 # 后注册 09:45 输出:App1 (因为先注册的App1先占用,后注册的App3同优先级,所以09:45被App1占用) 输入: 2 App3 5 09:30 10:30 # 先注册 App1 5 09:00 10:00 # 后注册 09:45 输出:App3 (因为先注册的App3先处理,占用了09:30-10:30,然后App1处理,09:00-09:30没有被占用,所以09:00-09:30是App1,09:30-10:00是App3,10:00-10:30是App3?不对,App1的时间段是09:00-10:00,但是09:30-10:00已经被App3占用了(同优先级,后注册的App1不能覆盖),所以App1只能注册09:00-09:30。因此09:45属于App3) 输入: 1 App1 3 12:00 12:01 12:00 输出:App1 (包含起始时间,不包含结束时间,所以12:00这一分钟在时间段内) 输入: 1 App1 3 12:00 12:00 # 无效 12:00 输出:NA 19. 注意:上面的代码中,我们使用了一个指针数组time_table,每个元素指向注册信息结构体中的name。由于结构体数组在排序后,每个结构体的name仍然有效,所以这样指向是安全的。 20. 但是,同一个App的多个时段,我们使用相同的name字符串(同一个结构体中的name),所以没有问题。 21. 运行环境:C语言标准。 22. 改进:如果输入的时间格式错误怎么办?题目保证两位,所以可以不做错误处理。 23. 提交代码。 注意:题目要求输出一个字符串,所以直接输出即可。 由于题目要求C语言实现,以上代码可以满足。 但是,我们注意到:在注册信息结构体中,我们存储了name(字符数组),这样在排序时,结构体交换可能会比较耗时,但是最多100条,所以没问题。 另一种优化:我们可以不存储整个结构体,而存储指针,但这里100条,直接复制结构体也可以。 因此,我们按照上述代码实现。&lt;/think&gt;以下是C语言实现的解决方案,根据时间段和优先级管理App注册,并在指定时间点查询使用哪个App。程序严格遵循输入输出规范,处理时间段冲突、优先级覆盖等逻辑。 ### 完整代码实现 ```c #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;string.h&gt; #define MAX_APPS 100 #define MAX_NAME_LEN 100 #define MINUTES_IN_DAY 1440 typedef struct { char name[MAX_NAME_LEN + 1]; int priority; int start_minute; int end_minute; int order; // 注册顺序 } AppRegistration; // 时间字符串转分钟数 int time_to_minutes(const char *time_str) { int hour, minute; sscanf(time_str, &quot;%d:%d&quot;, &amp;hour, &amp;minute); return hour * 60 + minute; } // 比较函数:优先级降序,同优先级时按注册顺序升序 int compare_apps(const void *a, const void *b) { const AppRegistration *app1 = (const AppRegistration *)a; const AppRegistration *app2 = (const AppRegistration *)b; if (app1-&gt;priority != app2-&gt;priority) { return app2-&gt;priority - app1-&gt;priority; // 优先级降序 } return app1-&gt;order - app2-&gt;order; // 注册顺序升序 } int main() { int n; scanf(&quot;%d&quot;, &amp;n); AppRegistration apps[MAX_APPS]; int valid_count = 0; // 读取注册信息 for (int i = 0; i &lt; n; i++) { char name[MAX_NAME_LEN + 1]; int priority; char start_time[6], end_time[6]; scanf(&quot;%s %d %s %s&quot;, name, &amp;priority, start_time, end_time); int start_min = time_to_minutes(start_time); int end_min = time_to_minutes(end_time); // 校验时间有效性 if (start_min &gt;= end_min) { continue; // 无效注册 } // 存储有效注册 strcpy(apps[valid_count].name, name); apps[valid_count].priority = priority; apps[valid_count].start_minute = start_min; apps[valid_count].end_minute = end_min; apps[valid_count].order = valid_count; // 记录注册顺序 valid_count++; } // 按优先级和注册顺序排序 qsort(apps, valid_count, sizeof(AppRegistration), compare_apps); // 初始化时间表(0-1439分钟) char *time_table[MINUTES_IN_DAY] = { NULL }; // 填充时间表(优先级高的先处理) for (int i = 0; i &lt; valid_count; i++) { int start = apps[i].start_minute; int end = apps[i].end_minute; for (int min = start; min &lt; end; min++) { // 只覆盖空闲时段(高优先级可覆盖低优先级,同优先级时先注册者保留) if (time_table[min] == NULL) { time_table[min] = apps[i].name; } } } // 读取查询时间 char query_time[6]; scanf(&quot;%s&quot;, query_time); int query_min = time_to_minutes(query_time); // 输出结果 if (query_min &gt;= 0 &amp;&amp; query_min &lt; MINUTES_IN_DAY &amp;&amp; time_table[query_min] != NULL) { printf(&quot;%s\n&quot;, time_table[query_min]); } else { printf(&quot;NA\n&quot;); } return 0; } ``` ### 关键设计说明 1. **数据结构**: - `AppRegistration` 结构体存储App的注册信息(名称、优先级、起止时间、注册顺序) - `time_table` 数组表示每分钟对应的App名称(1440个时间点) 2. **冲突处理逻辑**: - **高优先级覆盖低优先级**:排序后高优先级App先处理 - **同优先级先到先得**:后注册的App无法覆盖先注册的时段 - **时间有效性**:起始时间 &ge; 结束时间的注册被忽略 3. **时间处理**: - 将&quot;HH:MM&quot;格式转换为分钟数(0-1439) - 时间段包含起始时间点,不包含结束时间点(左闭右开) 4. **算法流程**: ```mermaid graph TD A[读取App数量N] --&gt; B[读取并验证注册信息] B --&gt; C{起始时间 &lt; 结束时间?} C -- 是 --&gt; D[存储有效注册] C -- 否 --&gt; B D --&gt; E[按优先级和注册顺序排序] E --&gt; F[初始化1440分钟时间表] F --&gt; G[遍历注册信息填充时间表] G --&gt; H[读取查询时间] H --&gt; I[输出App名称或NA] ``` ### 测试用例示例 #### 输入 1 ``` 2 App1 5 09:00 10:00 App2 4 09:30 10:30 09:30 ``` #### 输出 1 ``` App1 ``` **说明**:高优先级App1覆盖低优先级App2的冲突时段 #### 输入 2 ``` 3 WeChat 3 08:00 10:00 TikTok 5 09:30 10:30 Alipay 5 09:00 10:00 10:15 ``` #### 输出 2 ``` TikTok ``` **说明**: 1. TikTok优先级最高,完整注册09:30-10:30 2. Alipay与TikTok同优先级,但后注册的Alipay冲突部分失效 3. WeChat被高优先级覆盖,仅保留08:00-09:30 ### 使用注意事项 1. **输入规范**: - 第一行必须是整数N(&le;100) - 每行注册数据格式:`[App名称] [优先级] [起始时间] [结束时间]` - 时间格式必须为`HH:MM`(不足两位补零) 2. **边界处理**: - 无效时间段自动忽略 - 查询时间超出00:00-23:59返回&quot;NA&quot; - 分钟数计算包含起始点,不包含结束点 3. **性能保证**: - 时间复杂度:$O(N \log N + N \times L)$(L为最大时间段长度) - 空间复杂度:$O(1)$(固定1440个时间点存储) 此实现满足题目所有要求,包括优先级覆盖规则、时间段处理规则和冲突解决机制[^1][^2][^3][^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值