[Pergunta do pincel de linguagem C] Leetcode622 - projetar fila circular

Endereço do evento: Desafio de aprendizado de 21 dias da CSDN

Leetcode622 - Desenhar Fila Circular

descrição do tópico

Projete sua implementação de fila circular. Uma fila circular é uma estrutura de dados linear cujo funcionamento é baseado no princípio FIFO (first in first out) e o final da fila é conectado após o início da fila para formar um loop. Também é conhecido como "buffer de anel".
Um benefício das filas circulares é que podemos utilizar o espaço usado anteriormente nessa fila. Em uma fila normal, uma vez que a fila está cheia, não podemos inserir o próximo elemento, mesmo que ainda haja espaço na frente da fila. Mas com uma fila circular, podemos usar esse espaço para armazenar novos valores.

Link : https://leetcode.cn/problems/design-circular-queue

Sua implementação deve suportar as seguintes operações:

MyCircularQueue(k): Construtor, defina o comprimento da fila para k.
Front: Obtém elementos da frente da fila. Retorna -1 se a fila estiver vazia.
Rear: Pegue o elemento no final da fila. Retorna -1 se a fila estiver vazia.
enQueue(value): Insere um elemento na fila circular. Retorna verdadeiro se a inserção foi bem-sucedida.
deQueue(): Remove um elemento da fila circular. Retorna verdadeiro se a exclusão foi bem-sucedida.
isEmpty(): Verifica se a fila circular está vazia.
isFull(): Verifica se a fila circular está cheia.

Exemplo :

MyCircularQueue circularQueue = new MyCircularQueue(3); // Define o comprimento para 3
circularQueue.enQueue(1); // Retorna true
circularQueue.enQueue(2); // Retorna true
circularQueue.enQueue(3); // Retorna true
circularQueue enQueue(4); // retorna false, a fila está cheia
circularQueue.Rear(); // retorna 3
circularQueue.isFull(); // retorna true
circularQueue.deQueue(); // retorna true
circularQueue.enQueue(4 ); // retorna true
circularQueue.Rear(); // retorna 4


Dicas :

  • Todos os valores estão no intervalo de 0 a 1000;
  • Os operandos estarão no intervalo de 1 a 1000;
  • Não use a biblioteca de filas integrada.

padrão de código principal

typedef struct {
    
    

} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
    
    

}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    
    

}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    
    

}

int myCircularQueueFront(MyCircularQueue* obj) {
    
    

}

int myCircularQueueRear(MyCircularQueue* obj) {
    
    

}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    
    

}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    
    

}

void myCircularQueueFree(MyCircularQueue* 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);
*/

Análise de ideias e implementação de código (linguagem C)

Não é muito bom usar uma lista de encadeamento único. Por exemplo, se você deseja obter os elementos no final da fila, deve percorrê-la novamente, mas pode usar diretamente o subscrito -1 no final de a fila com a tabela de sequência. Além disso, a criação de uma lista de encadeamento único é mais problemática do que a tabela de sequência e você precisa usá-los um por um. Os nós são criados e todos estão vinculados. É melhor usar a tabela de sequência dinâmica.
A inserção ou exclusão de elementos na fila circular não altera o espaço, adotando-se a estratégia de sobrescrever. Na verdade, a chave para esta questão é determinar com precisão se está vazio ou cheio. Aqui deixamos o ponto traseiro apontar para a próxima posição do elemento no final da fila, e então surge o problema. Não podemos distinguir os dois estados de vazio e cheio. Por que?
Conforme mostrado na figura, tanto o ponteiro do início da fila quanto o ponteiro do final da fila apontam para a mesma posição nos estados vazio e cheio.
imagem.png

Solução :

  1. Incrementar um tamanho para contar
  2. Adicione um espaço, e sempre deixe um lugar quando estiver cheio, por exemplo, se a fila circular tiver 4 elementos, serão abertos 5 espaços.

A próxima posição da posição traseira é a frente, que é o estado cheio, e a frente e a traseira apontam para a mesma posição, que é o estado vazio. Porém, vale ressaltar que essa é a conclusão da estrutura lógica. Como mostra a figura, a fila da estrutura lógica está cheia, mas utilizamos uma tabela de sequência dinâmica para realizar a fila circular, mas a estrutura física é outra forma. Nossas operações devem ser baseadas na estrutura física.
imagem.png
Como mostra a figura, devemos prestar atenção em como lidar com isso, deixar o subscrito traseiro + 1 %N, N representa o número total de espaços (incluindo um espaço extra) e julgar se o resultado é igual ao da frente subscrito.
imagem.png
Declaração da estrutura e criação da fila
A lista circular é implementada usando uma tabela de sequência dinâmica, definindo o subscrito da cabeça e da cauda da fila e um N representando o número total de espaços abertos pela tabela de sequência dinâmica (mais um).
Crie uma fila para solicitar espaço no heap, assim como a tabela de sequência dinâmica, abra um espaço maior que o k fornecido e retorne o ponteiro da fila após a conclusão da inicialização.

typedef struct {
    
    
    int* arr;
    int front;
    int rear;
    int N;
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
    
    
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->arr = (int*)malloc((k+1)*sizeof(int));
    obj->front = obj->rear = 0;
    obj->N = k + 1;
    return obj;
}

Se a frente
e a retaguarda forem iguais, significa que a fila está vazia, e se o juízo estiver cheio, há duas situações que devem ser observadas, que foram citadas acima.

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    
    
    return obj->rear == obj->front;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    
    
    return ((obj->rear+1) % obj->N) == obj->front;
}

Se a fila do elemento
estiver cheia, não será permitido colocá-la e false será retornado. Se não estiver cheia, o elemento será colocado diretamente na posição traseira. Observe que você deve se lembrar de aguardar obj- >N. Isso é para controlar que, se a parte traseira atingir o final do espaço, ela poderá retornar à posição do subscrito 0, de modo a realizar o loop.

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    
    
    if(myCircularQueueIsFull(obj))
        return false;
    obj->arr[obj->rear] = value;
    ++obj->rear;
    obj->rear %= obj->N;
    return true;
}

Se o elemento estiver fora da fila
, ele não estará fora da fila e retornará falso. Se não estiver vazio, a frente será movida um bit para frente. Observe que você deve se lembrar de esperar por obj->N. Isso é para controlar que, se a parte traseira atingir o final do espaço, ela possa retornar à posição do subscrito 0, para realizar o loop.

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    
    
    if(myCircularQueueIsEmpty(obj))
        return false;
    ++obj->front;
    obj->front %= obj->N;
    return true;
}

Obtenha primeiro o elemento de cabeçalho da fila
para ver se a fila está vazia, se estiver vazia, retorne -1, se não estiver vazia, apenas retorne o elemento de cabeçalho da fila diretamente.

int myCircularQueueFront(MyCircularQueue* obj) {
    
    
    if(myCircularQueueIsEmpty(obj))
        return -1;
    return obj->arr[obj->front];
}

Para obter os elementos no final da fila,
primeiro verifique se a fila está vazia. Se estiver vazia, retorne -1. Se não estiver vazia, há duas situações a serem observadas: traseira é 0 e traseira não é 0.
Existem duas formas de escrever:

int myCircularQueueRear(MyCircularQueue* obj) {
    
    
    if(myCircularQueueIsEmpty(obj))
        return -1;
    else if(obj->rear == 0)
        return obj->arr[obj->N - 1];
    else
        return obj->arr[obj->rear - 1];
}


Existem duas estruturas que são criadas dinamicamente destruindo e liberando a fila , uma é uma estrutura de fila e a outra é uma matriz dinâmica.A matriz deve ser liberada primeiro e depois a estrutura.

void myCircularQueueFree(MyCircularQueue* obj) {
    
    
    free(obj->arr);
    obj->arr = NULL;
    obj->front = obj->rear = obj->N = 0;
    free(obj);
}

insira a descrição da imagem aqui

Acho que você gosta

Origin blog.csdn.net/weixin_61561736/article/details/126418702
Recomendado
Clasificación