データ構造のキューの実装(チャレンジプログラミング2)

データ構造のキューの実装

CPU がマルチタスクを処理する場合、キューの考え方が最も一般的ですが、最初に例を見てみましょう。

トピック

namei と処理時間 timei という名前の既存の n 個のタスクを一列に並べ、CPU はこれらのタスクをラウンドロビン スケジューリング方式で 1 ​​つずつ処理し、各タスクは最大 q ms で処理します (この時間がタイム スライスになります)。タスクが q ms 経過しても処理されなかった場合、タスクはキューの最後に移動され、CPU はすぐに次のタスクの処理を開始します。
例: q が 100 であるとすると、タスク キュー
A(150)—B(80)—C(200)—D(200) があり
、最初に A が 100ms 処理され、その後、タスク キューの最後に移動します。残り 50 ミリ秒でキューに戻ります。
B(80)—C(200)—D(200)—A(50)
次にBは80ms処理され、180msで処理が完了してキューから消えます。
C(200)—D(200)—A(50)
など
————————————————————————————————— ——— —

入力

nq
name1 time1
name2 time2
... ...
最初の行に、タスクの数を表す整数 n とタイム スライスを表す整数 q をスペースで区切って入力します。
次の n 行には、各タスクの情報が入力されます。文字列名と timei はスペースで区切られます。

出力

各タスク名と終了時刻をタスクの完了順に出力します。タスク名と終了時刻はスペースで区切られ、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. ヘッドはヘッド ポインターとして使用され、デキューは毎回ヘッドが指す要素を取り出します。 。
3. 末尾はキューの末尾を指し、その値は n+1 です。各エンキューは、処理されたデータをデータの末尾の後ろに格納します。
4. enqueue (x) 関数。キューに要素を追加します。パラメータであることに注意してください。
5. dequeue () 関数。要素を取り出すために使用される関数です。
プログラムを実行するとQの先頭から要素が取り出され、処理後にenqueueでtailで示される位置に追加されます。このプロセスは、先頭と末尾が等しくなり、プロセスが完了するまで継続されます。

ただし、これを行うには、まず配列の長さが十分であることを確認する必要があります。そうでないと、tail+1 によって配列の添え字が範囲外になる可能性が高くなります。大きなデータを扱う場合、配列の長さは非常に長くなる可能性があります。
この状況を回避したい場合は、ヘッド ポインタを 0 に保ち、dequeue( を実行するたびにすべてのデータを配列の先頭に移動する必要があります) )。欠点は、各移動が O(n) 個の複雑さを追加することです。
この本の解決策は、リング バッファを使用してデータを管理することです。
代替
秒針のようなもので、tail+1=12が配列の範囲を超えた場合は0となります。同様に1分経過すると1秒から計算が始まります。

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

これら 2 つの式は、配列データの数を超えると先頭と末尾が 0 に設定されます。

リング バッファは、デキュー操作とエンキュー操作を同時に O(1) の複雑さで実装できます。

キューとスタックは、注意深く研究する価値のある 2 つの単純なデータ構造です。

おすすめ

転載: blog.csdn.net/qq_32577169/article/details/94970351