タイトル説明
622.循環キューを設計する-LeetCode(LeetCode)
循環キューの実装を設計します。循環キューは線形データ構造であり、その動作はFIFO(先入れ先出し)の原則に基づいており、行の終わりは行の先頭の後に接続されてループを形成します。「リングバッファ」とも呼ばれます。
循環キューの利点の1つは、このキューの以前に使用されたスペースを使用できることです。通常のキューでは、キューがいっぱいになると、キューの前にまだスペースがある場合でも、次の要素を挿入できません。ただし、循環キューを使用すると、これらのスペースを使用して新しい値を格納できます。
実装は次の操作をサポートする必要があります。
•MyCircularQueue(k):コンストラクター。キューの長さをkに設定します。
•フロント:チームのトップから要素を取得します。キューが空の場合は、-1を返します。
•リア:テールエレメントを取得します。キューが空の場合は、-1を返します。
•enQueue(value):要素を循環キューに挿入します。正常に挿入されるとtrueを返します。
•deQueue():循環キューから要素を削除します。正常に削除されるとtrueを返します。
•isEmpty():循環キューが空かどうかを確認します。
•isFull():循環キューがいっぱいかどうかを確認します。
例1:
MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1); // 返回 true
circularQueue.enQueue(2); // 返回 true
circularQueue.enQueue(3); // 返回 true
circularQueue.enQueue(4); // 返回 false,队列已满
circularQueue.Rear(); // 返回 3
circularQueue.isFull(); // 返回 true
circularQueue.deQueue(); // 返回 true
circularQueue.enQueue(4); // 返回 true
circularQueue.Rear(); // 返回 4
思考分析
この問題は配列を使用して実装されます。2つのポインタが与えられると、1つはキューの先頭(フロント)を指し、もう1つはキューの末尾(リア)を指します。Rear+ 1 = Frontの場合、循環キューはいっぱいです。また、Rear = Frontの場合、循環キューは空です。
•配列、ヘッドポインター、テールポインター、キュー内のカウント数を含む構造を作成します。
typedef struct {
int* a;
//头
int Front;
//尾
int Rear;
int k;
} MyCircularQueue;
•キューを初期化し、k + 1 intサイズのスペースを開き、ヘッドポインタとテールポインタを0に等しくします。
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* p = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
p->a = (int*)malloc((k + 1) * sizeof(int));
p->Front = p->Rear = 0;
p->k = k;
return p;
}
•データを入力するには、最初にキューがいっぱいかどうか、いっぱいの場合は直接false、いっぱいでない場合は値を直接テールポインターに置き、テールポインターの場合はテールポインターを+1にします。 k + 1の位置を指し、Rear = 0に設定します
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
obj->a[obj->Rear] = value;
++obj->Rear;
if(obj->Rear == obj->k + 1)
{
obj->Rear = 0;
}
return true;
}
•データを削除するには、最初にキューが空かどうか、空の場合は直接false、空でない場合は+ヘッドポインタ、ヘッドポインタの位置がk + 1の場合は、Frontを0とします。
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return false;
}
++obj->Front;
if(obj->Front == obj->k + 1)
obj->Front = 0;
return true;
}
•ヘッドノードに戻り、最初にキューが空かどうかを判断します。キューが空の場合は直接-1を返し、空でない場合はヘッドポインタが指すノードに直接戻ります。
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
else
{
return obj->a[obj->Front];
}
}
•テールノードに戻り、最初にキューが空かどうかを判断します。キューが空の場合は直接-1を返し、空でない場合はリア-1のノードに戻ります。
特殊なケース:Rear = 0の場合、Rearを許可します。-1 = k
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
int prev = obj->Rear - 1;
if(obj->Rear == 0)
{
prev = obj->k;
}
return obj->a[prev];
}
•キューが空かどうかを判断します。ヘッドポインタとテールポインタが等しい場合、キューは空です。キューが空の場合はtrueを返します。空でない場合はfalseを返します。
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
if(obj->Front == obj->Rear)
{
return true;
}
else
{
return false;
}
}
•循環キューがいっぱいで空であるため、キューがいっぱいかどうかを判断します。キューがいっぱいになると、キューの先頭と末尾の間に距離があります。すべて、Rear + 1 = Frontの場合、防止するためにいっぱいになります。配列の添え字を超えているため、Rear +1がk + 1の位置に移動するときは、Rear + 1を0に設定して、サイクルが満たされるようにします。
bool myCircularQueueIsFull(MyCircularQueue* obj) {
int next = obj->Rear + 1;
//让下标循环,如果next超过数组,则置为0
//防止判满next超过数组下标
if(next == obj->k + 1)
{
next = 0;
}
//判满如果Rear+1==Front则满了true,否则没满false
if(next == obj->Front)
{
return true;
}
else
{
return false;
}
}
コード
typedef struct {
int* a;
//头
int Front;
//尾
int Rear;
int k;
} MyCircularQueue;
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
bool myCircularQueueIsFull(MyCircularQueue* obj);
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* p = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
p->a = (int*)malloc((k + 1) * sizeof(int));
p->Front = p->Rear = 0;
p->k = k;
return p;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
obj->a[obj->Rear] = value;
++obj->Rear;
if(obj->Rear == obj->k + 1)
{
obj->Rear = 0;
}
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return false;
}
++obj->Front;
if(obj->Front == obj->k + 1)
obj->Front = 0;
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;
int prev = obj->Rear - 1;
if(obj->Rear == 0)
{
prev = obj->k;
}
return obj->a[prev];
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
if(obj->Front == obj->Rear)
{
return true;
}
else
{
return false;
}
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
int next = obj->Rear + 1;
//让下标循环,如果next超过数组,则置为0
//防止判满next超过数组下标
if(next == obj->k + 1)
{
next = 0;
}
//判满如果Rear+1==Front则满了true,否则没满false
if(next == obj->Front)
{
return true;
}
else
{
return false;
}
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
obj->a = NULL;
free(obj);
}
/**
* Your MyCircularQueue struct will be instantiated and called as such:
* MyCircularQueue* obj = myCircularQueueCreate(k);
* bool param_1 = myCircularQueueEnQueue(obj, value);
* bool param_2 = myCircularQueueDeQueue(obj);
* int param_3 = myCircularQueueFront(obj);
* int param_4 = myCircularQueueRear(obj);
* bool param_5 = myCircularQueueIsEmpty(obj);
* bool param_6 = myCircularQueueIsFull(obj);
* myCircularQueueFree(obj);
*/