数据结构之队列的实现(挑战程序设计2)

数据结构之队列的实现

队列的思想在cpu处理多任务是最为常见,先看一个例子。

题目

现有名称为namei且处理时间为timei 的n个任务顺序排成一列,CPU通过循环调度法逐一处理这些任务每个任务最多处理q ms(这个时间成为时间片)。如果q ms之后任务尚未处理完毕,那么该任务将被移动至队伍最末尾,CPU随即开始处理下一个任务。
例子:假设q是100,然后有如下任务队列
A(150)—B(80)—C(200)—D(200)
首先A被处理100ms,然后带着剩余的50ms移动至队列尾。
B(80)—C(200)—D(200)—A(50)
接下来B被处理80ms,在第180ms时完成处理从队列中消失。
C(200)—D(200)—A(50)
依次类推
———————————————————————————————————

输入

n q
name1 time1
name2 time2
… …
第1行输入表示任务数的整数n与表示时间片的整数q,用1个空格隔开。
接下来n行输入各任务的信息。字符串name与timei用1个空格隔开。

输出

按照任务完成的先后顺序输出各任务名以及结束时间,任务名与对应结束时间用空格隔开,每一对任务名与结束时间占1行。

限制

1 ≤ n ≤ 100 000
1 ≤ q ≤ 1000
1 ≤ timei ≤ 50 000
1 ≤ 字符串namei的长度 ≤ 10
1 ≤ timei的和 ≤ 1 000 000

输入示例

5 100
p1 150
p2 80
p3 200
p4 350
p5 20

输出示例

p2 180
p5 400
p1 450
p3 550
p4 800

先看代码

#include<stdio.h>
#include<string.h>
#define LEN 10005

typedef struct PP {
    
    
	char name[100];
	int t;
} P;

P Q[LEN];

int head, tail, n;          //n代表总任务数

bool isEmpty() {
    
    
	return head == tail;
}

void enqueue(P x) {
    
              //该函数用来向队列尾添加元素
	Q[tail] = x;
	tail = (tail + 1) % LEN;
}

P dequeue() {
    
                   //该函数用来从队列前取出元素
	P x = Q[head];
	head = (head + 1) % LEN;
	return x;
}

int min(int a, int b) {
    
     return a < b ? a : b; }

int main()
{
    
    
	int elaps = 0, c;
	int i, q;                    //q代表的是时间片
	P u;
	scanf("%d %d", &n, &q);
	//按顺序添加任务到队列
	for (i = 1; i <= n ; i++)
	{
    
    
		scanf("%s", Q[i].name);
		scanf("%d", &Q[i].t);
	}
	head = 1; tail = n + 1;

	while (tail != head)
	{
    
    
		u = dequeue();
		c = min(q, u.t);
		u.t -= c;
		elaps += c;
		if (u.t > 0)
		{
    
    
			enqueue(u);
		}
		else
		{
    
    
			printf("%s %d\n", u.name, elaps);
		}
	}
	return 0;
}

使用数组可以模拟队列,主要需要以下变量以及函数
1.储存数据的数组:Q
2.用作头指针的head,dequeue每次会取出head所指的元素。
3.指向队列尾的tail,他的值是n+1,每次enqueue会将处理好的数据存储在数据末尾的后边。
4.enqueue(x)函数,向队列中添加元素,注意他是有参的
5.dequeue()函数,用来取出元素的函数。
在程序运行时,首先会从Q的开头取出元素在处理之后用enqueue将其添加到tail所指的位置。这样一次处理下去,知道head与tail相等时,处理完成。

不过这样做首先需要保证数组的长度足够,否则当tail+1是很容易发生数组下标越界。在处理大型数据时,数组的长度可能会十分恐怖
如果想要避免这种情况,则需要将head指针常保持在0,而每次执行完dequeue()之后将所有数据向数组开头移动。缺点是,每次移动会增加O(n)的复杂度。
书中的解决办法时使用环形缓冲区来管理数据。
Alt
可以将其理解为秒针,当tail+1=12超出了数组的范围的时候,就将其置为0。类似于1分钟过去了,又从1秒开始计算。

//对head和tail的操作
head = (head + 1) % MAX      //MAX表示数组元素个数
tail = (tail + 1) % MAX      

这两个表达式会将head和tail超出数组数据个数时将其置为0。

环形缓冲区可以同时以复杂度O(1)实现dequeue和enqueue的操作。

队列以及栈作为两种简单的数据结构值得去认真学习。

猜你喜欢

转载自blog.csdn.net/qq_32577169/article/details/94970351