- FIFO(ファースト・イン/ファースト・アウト)のロジックについて教えてほしい
- 言葉ではやりたいことは分かるけど、プログラムとしてはどう実装していいか分からない
- イラストで仕組みについて教えてほしい
FIFOについては基本情報/応用情報技術者試験や、プログラミングの本にも幾度となく登場します。
最初に入れたデータを最初に取り出すという概念は頭では理解できるものの、いざ実装するとなると、どうやっていいか分からないものです。
FIFOについて解説した記事は多いですが、どれも言葉で長々と説明されているだけで、処理のイメージがしづらい。
今回はそんなFIFOについて、いざ実装するとなった時に、どのようにロジックを組めばよいかイラストで示しつつ分かりやすく解説したいと思います!
まずは基本的なルール
FIFOは「キュー」と呼ばれる配列にデータを格納していきます。
先頭からデータを格納していって、キューが全部埋まれば、それ以上データを格納しません。
データを取り出すときは先頭(要するに一番古く格納したデータ)から取り出します。
またデータはリング(循環)バッファ形式で、先頭から順次データを格納していくのですが、一番うしろまで来たらまた先頭からデータを格納しようとします。
イラストでロジックを解説
初期状態について
最初にキューはすべて空(もしくは0で埋める)にしておきます。
そしてキューがどれだけ埋まっているかはcount(要素数)で管理します
キューを追加すると
まずは数字の10を追加してみます。
キューにひとつデータを格納したので、count(要素数)は0→1。
rear(末尾位置)で次に格納すべき場所を示すので、rearも0→1に移動させます。
更にキューに追加
20、30、40を追加します。
countもrearも数字を進めます。
最初に追加した10を取り出してみる
取り出しを行うときはfront(先頭位置)から取り出します。
取り出しを行ったらrear同様frontも進めます。そしてcountも減らします。
キューが全部埋まっていたら
先程の状態から50、60を追加します。
するとキューは満杯の状態になるので、rearとfrontが同一のところを指します。
そこに70を追加しようとすると、count(要素数)は5になっているので、追加の受付を拒否します。
以上がFIFOのロジックです。
FIFOのコード例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
#include <stdio.h> #define SIZE 5 // キューの最大サイズ typedef struct { int data[SIZE]; // キューのデータを格納する配列 int front; // キューの先頭を指すインデックス(取り出し側) int rear; // キューの末尾を指すインデックス(追加側) int count; // キュー内の要素数を管理する変数 } Queue; // キューを初期化する関数 void initQueue(Queue *q) { q->front = 0; // 先頭を0に初期化 q->rear = 0; // 末尾を0に初期化 q->count = 0; // 要素数を0に初期化 } // キューにデータを追加する関数(Enqueue) int enqueue(Queue *q, int value) { if (q->count == SIZE) { // 要素数が最大サイズと等しい場合、満杯と判定 printf("Queue is full!\n"); return -1; } q->data[q->rear] = value; // rear の位置にデータを格納 q->rear = (q->rear + 1) % SIZE; // rear を次の位置に移動(循環バッファ対応) q->count++; // 要素数を増やす return 0; } // キューからデータを取り出す関数(Dequeue) int dequeue(Queue *q) { if (q->count == 0) { // 要素数が0の場合、空と判定 printf("Queue is empty!\n"); return -1; } q->front = (q->front + 1) % SIZE; // front を次の位置に移動(循環バッファ対応) q->count--; // 要素数を減らす return 0; } // キューの中身を表示する関数 void printQueue(Queue *q) { int i = q->front; // 先頭から開始 int elements = q->count; // キュー内の要素数を取得 printf("Queue: "); while (elements > 0) { // 要素数がある限りループ printf("%d ", q->data[i]); // 現在のデータを出力 i = (i + 1) % SIZE; // 次のデータに移動(循環バッファ対応) elements--; // ループ回数を減らす } printf("\n"); } int main() { Queue q; // キューのインスタンスを作成 initQueue(&q); // キューを初期化 int val; //デキュー時の値取得用変数 enqueue(&q, 10); // 10 をキューに追加 enqueue(&q, 20); // 20 をキューに追加 enqueue(&q, 30); // 30 をキューに追加 enqueue(&q, 40); // 40 をキューに追加 dequeue(&q); // 10 を取り出し enqueue(&q, 50); // 50 をキューに追加 enqueue(&q, 60); // 60 をキューに追加(最大サイズまで埋まる) enqueue(&q, 70); // キューが満杯なので、追加できない printQueue(&q); // キューの中身を表示 return 0; } |
1 2 |
Queue is full! Queue: 20 30 40 50 60 |
以上がFIFOのロジックとコードでした。
FIFOはコードにすると難しそうに見えますが、イラストでロジックの動きがわかると案外簡単なものです。
これ以外にもFIFOを実現するコードは無数にありますが、今回は一番シンプルなコードということでこちらを紹介しました!