PTA_7-8 Windows消息队列

7-7 Windows消息队列 (25 分)

消息队列是Windows系统的基础。对于每个进程,系统维护一个消息队列。如果在进程中有特定事件发生,如点击鼠标、文字改变等,系统将把这个消息加到队列当中。同时,如果队列不是空的,这一进程循环地从队列中按照优先级获取消息。请注意优先级值低意味着优先级高。请编辑程序模拟消息队列,将消息加到队列中以及从队列中获取消息。

输入格式:
输入首先给出正整数N(≤10​5​​),随后N行,每行给出一个指令——GET或PUT,分别表示从队列中取出消息或将消息添加到队列中。如果指令是PUT,后面就有一个消息名称、以及一个正整数表示消息的优先级,此数越小表示优先级越高。消息名称是长度不超过10个字符且不含空格的字符串;题目保证队列中消息的优先级无重复,且输入至少有一个GET。

输出格式:
对于每个GET指令,在一行中输出消息队列中优先级最高的消息的名称和参数。如果消息队列中没有消息,输出EMPTY QUEUE!。对于PUT指令则没有输出。

输入样例:

9
PUT msg1 5
PUT msg2 4
GET
PUT msg3 2
PUT msg4 4
GET
GET
GET
GET

输出样例:

msg2
msg3
msg4
msg1
EMPTY QUEUE!

思路:
最小堆的运用问题,先直接照搬了教材(《数据结构》浙大陈越版)的标程,再创建结构体数组存消息和权值,权值作为元素进行最小堆的增删改查即可。遇到GET就取出最小的权值,再找到最小权值对应的消息输出。需要注意可能有重复权值对应不同的消息,只是它们存在于不同的时刻而已,所以输出后需要更新权值为一个取不到的值(-1)。码代码的时候就想到有可能会在大规模数据下超时,交一发果然超了,毕竟由权值找消息的操作是遍历结构体数组,太费时间。(以下是超时代码)

超时代码

#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define MINDATA  0
#define ERROR -1

typedef int ElementType;
typedef struct HNode * Heap;
struct HNode
{
	ElementType *Data;  //存储元素的数组
	int size;  			//堆中当前元素个数
	int Capacity; 		//堆的最大容量
};
typedef Heap MinHeap; 	//最小堆

MinHeap CreatHeap(int MaxSize)
{	//创建容量为MaxSize的空的最小堆
	MinHeap H = (MinHeap)malloc(sizeof(struct HNode));
	H -> Data = (ElementType *)malloc((MaxSize + 1) * sizeof(ElementType));
	H -> size = 0;
	H -> Capacity = MaxSize;
	H -> Data[0] = MINDATA;  //定义“哨兵”为最小堆中所有可能元素的值

	return H;
}

bool IsFull(MinHeap H)
{
	return (H -> size == H -> Capacity);
}

bool Insert(MinHeap H, ElementType X)
{
	int i;

	if(IsFull(H))
	{
		printf("最大堆已满\n");
		return false;
	}
	i = ++ H -> size;	//新增结点
	for( ; H -> Data[i/2] > X; i/=2)
	{
		H -> Data[i] = H -> Data[i/2];  //上滤X
	}
	H -> Data[i] = X;
	return true;
}

bool IsEmpty(MinHeap H)
{
	return (H -> size == 0);
}

ElementType DeleteMin(MinHeap H)
{	//从最小堆H中取出键值为最大的元素,并删除一个结点(重点在安置最后一个结点)
	int Parent, Child;
	ElementType MinItem, X;

	if(IsEmpty(H))
	{
		printf("EMPTY QUEUE!\n");
		return ERROR;
	}

	MinItem = H -> Data[1];		//取出根结点
	//用最小堆中最后一个元素从根结点开始向上过滤下层结点
	X = H -> Data[H -> size--];		//注意当前堆的规模要减小
	for(Parent = 1; Parent*2 <= H->size; Parent = Child)
	{
		Child = Parent * 2;
		if((Child != H -> size) && (H -> Data[Child] > H -> Data[Child+1]))
			Child++;	//Child指向左右子结点中的较小者
		if(X <= H -> Data[Child])
			break;	//找到合适的位置
		else
			H -> Data[Parent] = H -> Data[Child];
	}
	H -> Data[Parent] = X;

	return MinItem;
}

int main(int argc, char const *argv[])
{
	int N;
	int i = 0, j = 0;
	char order[5];
	struct message
	{
		char str[12];
		int weight;
	}msg[100000];

	scanf("%d", &N);
	MinHeap H = CreatHeap(N);
	for(i=0; i<N; i++)
	{
		scanf("%s", order);
		if(!strcmp(order, "PUT"))
		{
			scanf("%s %d", msg[j].str, &msg[j].weight);
			Insert(H, msg[j].weight);
			j++;
		}
		else if(!strcmp(order, "GET"))
		{
			ElementType result;
			result = DeleteMin(H);
			if(result != ERROR)
			{
				int k;
				for(k=0; k<=j; k++)
				{
					if(msg[k].weight == result)
					{
						printf("%s\n", msg[k].str);
						msg[k].weight = -1;
						break;
					}
				}
			}
		}
	}
	return 0;
}

改进:
在网上找了很多大佬的代码还是不得解(不会C++ STL哭晕在厕所)。注意到题目保证队列中消息的优先级(权值)无重复,于是可以在结构体数组下标上下手,这样就不用在Insert()和DeleteMin()函数中加参数来存权值对应消息内容或者是别的方法了(想想就麻烦)。做法:把结构体数组的成员改成char* str并且去掉权值weight,然后以权值weight作为结构体数组下标即可。这样一来msg[weight].str就对应着相应信息,直接输出就好了。
依旧存在的问题:
现在的代码能过了,但是由于输入时遇到GET就输出了,输出形式和实例不一样(巨丑),懒得改了。。。

AC代码

#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define MINDATA  0
#define ERROR -1

typedef int ElementType;
typedef struct HNode * Heap;
struct HNode
{
	ElementType *Data;  //存储元素的数组
	int size;  			//堆中当前元素个数
	int Capacity; 		//堆的最大容量
};
typedef Heap MinHeap; 	//最小堆

MinHeap CreatHeap(int MaxSize)
{	//创建容量为MaxSize的空的最小堆
	MinHeap H = (MinHeap)malloc(sizeof(struct HNode));
	H -> Data = (ElementType *)malloc((MaxSize + 1) * sizeof(ElementType));
	H -> size = 0;
	H -> Capacity = MaxSize;
	H -> Data[0] = MINDATA;  //定义“哨兵”为最小堆中所有可能元素的值

	return H;
}

bool IsFull(MinHeap H)
{
	return (H -> size == H -> Capacity);
}

bool Insert(MinHeap H, ElementType X)
{
	int i;

	if(IsFull(H))
	{
		printf("最大堆已满\n");
		return false;
	}
	i = ++ H -> size;	//新增结点
	for( ; H -> Data[i/2] > X; i/=2)
	{
		H -> Data[i] = H -> Data[i/2];  //上滤X
	}
	H -> Data[i] = X;
	return true;
}

bool IsEmpty(MinHeap H)
{
	return (H -> size == 0);
}

ElementType DeleteMin(MinHeap H)
{	//从最小堆H中取出键值为最大的元素,并删除一个结点(重点在安置最后一个结点)
	int Parent, Child;
	ElementType MinItem, X;

	if(IsEmpty(H))
	{
		printf("EMPTY QUEUE!\n");
		return ERROR;
	}

	MinItem = H -> Data[1];		//取出根结点
	//用最小堆中最后一个元素从根结点开始向上过滤下层结点
	X = H -> Data[H -> size--];		//注意当前堆的规模要减小
	for(Parent = 1; Parent*2 <= H->size; Parent = Child)
	{
		Child = Parent * 2;
		if((Child != H -> size) && (H -> Data[Child] > H -> Data[Child+1]))
			Child++;	//Child指向左右子结点中的较小者
		if(X <= H -> Data[Child])
			break;	//找到合适的位置
		else
			H -> Data[Parent] = H -> Data[Child];
	}
	H -> Data[Parent] = X;

	return MinItem;
}

int main(int argc, char const *argv[])
{
	int N;
	int i = 0, j = 0;
	char order[5];
	struct message
	{
		char *str;
	}msg[100002];

	scanf("%d", &N);
	MinHeap H = CreatHeap(N);
	for(i=0; i<N; i++)
	{
		scanf("%s", order);
		if(!strcmp(order, "PUT"))
		{
			char temp[12];
			int weight;
			scanf("%s %d", temp, &weight);	//数据暂存 
			msg[weight].str = (char*)malloc(sizeof(char)*12);	//给str分配空间 
			msg[weight].str = strcpy(msg[weight].str, temp);	//字符串赋值(返回char*类型) 
			Insert(H, weight);
		}
		else if(!strcmp(order, "GET"))
		{
			ElementType result;
			result = DeleteMin(H);
			if(result != ERROR)
			{
				printf("%s\n", msg[result].str);
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值