[LeetCode]-622. 循環キューを設計する

目次

662. 循環キューを設計する

トピック

アイデア

コード


662. 循環キューを設計する

622. 循環キューの設計 - LeetCodeicon-default.png?t=N7T8https://leetcode.cn/problems/design-circular-queue/

トピック

循環キューの実装を設計します。循環キューは線形データ構造であり、その動作は FIFO (先入れ先出し) 原理に基づいており、キューの最後尾がキューの先頭の後に接続されてループを形成します。 「リングバッファ」とも呼ばれます。

循環キューの利点の 1 つは、このキュー内で以前に使用されていたスペースを利用できることです。通常のキューでは、キューがいっぱいになると、キューの先頭にまだスペースがある場合でも、次の要素を挿入できません。しかし、循環キューを使用すると、このスペースを新しい値の保存に使用できます。

実装では次の操作をサポートする必要があります。

  • MyCircularQueue(k): コンストラクター、キューの長さを k に設定します。
  • Front: キューの先頭から要素を取得します。キューが空の場合は、-1 が返されます。
  • Rear: キューの末尾要素を取得します。キューが空の場合は、-1 が返されます。
  • enQueue(value): 要素を循環キューに挿入します。挿入が成功した場合は true を返します。
  • deQueue(): 循環キューから要素を削除します。削除が成功した場合は true を返します。
  • isEmpty(): 循環キューが空かどうかを確認してください。
  • isFull(): 循環キューがいっぱいかどうかを確認します。

例:

アイデア

k 個の有効な要素を格納できるサイズ k+1 の配列を開きます。キュー フロントの先頭とキュー リアの後部が配列の添字です。データの挿入と削除中に前部と後部の位置が移動します。配列の終端を超えると配列の先頭位置に戻り、ループを形成して循環キューの効果を実現します。

循環キューを実装すると、次のような効果が得られます。

難易度1:

rear は配列の末尾にデータを挿入します:rear が配列の末尾に到達したら、データを後部に挿入する必要があり、rear は配列の先頭にループバックする必要があります。直接後方ではなく配列++ 以上です。

解決:

  • モジュロのアイデア: 以下に示すように、rear++ は配列の長さ k+1 を変調し、配列の末尾を超えた後に配列の先頭に戻ります。 

難易度2:

フロントが配列の最後にある場合はデータを削除します。フロントが配列の最後にある場合は、キューの先頭から要素を削除する必要があります。先頭が配列の末尾を越えて移動されます。

解決:

  • モジュロのアイデア: 以下に示すように、フロントが配列の末尾を超えると、配列の長さ k+1 をモジュロして、フロントは配列の先頭に戻ります。

難易度3:

キューの末尾要素を取得する: 後部が配列インデックス 0 の位置にある場合、後部は -1 ~ -1 の位置にあり、末尾要素は配列の末尾の位置。

解決:

  • if文を追加し、rearが添字0の位置にあるとき、キューの末尾要素の位置を添字k+1とします。
  • モジュロのアイデア: 以下に示すように添え字 (rear+(k+1)-1)%(k+1) を削除する場合:

コード

(次の関数には、サウンディングやフルサウンディングなど、呼び出される関数が含まれています。これらの関数は前に配置する必要があります。最初に宣言してから使用してください。

typedef struct {
    int* a;//起始地址
    int front;//数组下标
    int rear;//数组下标
    int k;//有效数据个数
} MyCircularQueue;


//构造器
MyCircularQueue* myCircularQueueCreate(int k) {
    //结构体开辟空间
    MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    //数组开辟空间,多开辟一个可区分满和空
    obj->a=(int*)malloc(sizeof(int)*(k+1));
    //开始是空的状态
    obj->front=obj->rear=0;
    //传入的数(有效个数)给给k
    obj->k=k;

    return obj;
}
//探空和探满尽量位置往前放
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front==obj->rear;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->rear+1)%(obj->k+1)==(obj->front);
}

//插入一个元素 成功返回真
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    //判断是否满
    if(myCircularQueueIsFull(obj))
        return false;
    //插入rear位置
    obj->a[obj->rear]=value;
    obj->rear++;
    //模上一个数组的长度,rear超过到数组尾可以循环回到数组头
    obj->rear%=(obj->k+1);
    return true;
}
//删除
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    //判断是否为空
    if(myCircularQueueIsEmpty(obj))
        return false;

    //队头front往后移 ++front
    ++obj->front;
    //取模可在超过队尾时回到队头,取模不影响中间的移动
    obj->front%=(obj->k+1);
    return true;
}

//取队头元素
int myCircularQueueFront(MyCircularQueue* obj) {
    //探空
    if(myCircularQueueIsEmpty(obj))
        return -1;
    else
        return obj->a[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return -1;
    else
        //模上k+1  rear+(k+1)-1 % (k+1)
        return obj->a[(obj->rear+obj->k) % (obj->k+1)];
}


void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    free(obj);
}

おすすめ

転載: blog.csdn.net/m0_64476561/article/details/134348913