Принцип FIFO (First In, First Out)

Материал из m6a
Перейти к: навигация, поиск

Принцип FIFO (First In, First Out) — это принцип организации данных, при котором первый добавленный элемент является первым, который будет извлечен. Этот принцип является основой для структуры данных, называемой очередью (queue).

Основные понятия

  1. Очередь (Queue): Абстрактная структура данных, представляющая собой упорядоченную коллекцию элементов, в которой добавление элементов происходит в конец очереди (rear), а удаление элементов происходит из начала очереди (front).
  2. Начало очереди (Front): Место, откуда происходит удаление элементов из очереди.
  3. Конец очереди (Rear): Место, куда происходит добавление элементов в очередь.
  4. Добавление элемента (Enqueue): Операция добавления нового элемента в конец очереди.
  5. Удаление элемента (Dequeue): Операция удаления элемента из начала очереди.
  6. Первый вошел, первым вышел (First In, First Out - FIFO): Элемент, добавленный в очередь первым, будет удален из очереди первым.

Свойства FIFO

  1. Упорядоченность: Элементы в очереди хранятся в определенном порядке, который определяется порядком их добавления.
  2. Ограниченный доступ: Доступ к элементам очереди ограничен началом и концом очереди. Невозможно получить доступ к элементам, находящимся внутри очереди, без удаления элементов из начала очереди.
  3. Справедливость: Элементы обслуживаются в порядке их поступления, что обеспечивает справедливость при обработке данных.

Операции над очередью

  1. Enqueue (Добавление): Добавляет новый элемент в конец очереди.
    1. Сложность: $O(1)$
  2. Dequeue (Удаление): Удаляет элемент из начала очереди и возвращает его значение.
    1. Сложность: $O(1)$
  3. Peek (Просмотр): Возвращает значение элемента, находящегося в начале очереди, не удаляя его.
    1. Сложность: $O(1)$
  4. isEmpty (Проверка на пустоту): Проверяет, является ли очередь пустой. Возвращает `true`, если очередь пуста, и `false` в противном случае.
    1. Сложность: $O(1)$
  5. size (Размер): Возвращает количество элементов в очереди.
    1. Сложность: $O(1)$

Реализация очереди

Очередь можно реализовать с использованием массивов или связных списков. Существуют различные типы очередей, такие как линейная очередь и циклическая очередь.

  1. Реализация очереди с использованием массива (линейная очередь):
    1. ```python
    2. class Queue:
    3. def __init__(self, capacity):
    4. self.capacity = capacity
    5. self.arr = [None] * capacity
    6. self.front = 0
    7. self.rear = -1
    8. self.size = 0
    9. def enqueue(self, data):
    10. if self.size == self.capacity:
    11. print("Queue Overflow")
    12. return
    13. self.rear += 1
    14. self.arr[self.rear] = data
    15. self.size += 1
    16. def dequeue(self):
    17. if self.size == 0:
    18. print("Queue Underflow")
    19. return None
    20. data = self.arr[self.front]
    21. self.arr[self.front] = None
    22. self.front += 1
    23. self.size -= 1
    24. return data
    25. def peek(self):
    26. if self.size == 0:
    27. print("Queue is empty")
    28. return None
    29. return self.arr[self.front]
    30. def isEmpty(self):
    31. return self.size == 0
    32. def size(self):
    33. return self.size
    34. ```
  1. Реализация очереди с использованием массива (циклическая очередь):
    1. ```python
    2. class CircularQueue:
    3. def __init__(self, capacity):
    4. self.capacity = capacity
    5. self.arr = [None] * capacity
    6. self.front = 0
    7. self.rear = -1
    8. self.size = 0
    9. def enqueue(self, data):
    10. if self.size == self.capacity:
    11. print("Queue Overflow")
    12. return
    13. self.rear = (self.rear + 1) % self.capacity
    14. self.arr[self.rear] = data
    15. self.size += 1
    16. def dequeue(self):
    17. if self.size == 0:
    18. print("Queue Underflow")
    19. return None
    20. data = self.arr[self.front]
    21. self.arr[self.front] = None
    22. self.front = (self.front + 1) % self.capacity
    23. self.size -= 1
    24. return data
    25. def peek(self):
    26. if self.size == 0:
    27. print("Queue is empty")
    28. return None
    29. return self.arr[self.front]
    30. def isEmpty(self):
    31. return self.size == 0
    32. def size(self):
    33. return self.size
    34. ```
  1. Реализация очереди с использованием связного списка:
    1. ```python
    2. class Node:
    3. def __init__(self, data):
    4. self.data = data
    5. self.next = None
    6. class Queue:
    7. def __init__(self):
    8. self.front = None
    9. self.rear = None
    10. self.size = 0
    11. def enqueue(self, data):
    12. new_node = Node(data)
    13. if self.rear is None:
    14. self.front = new_node
    15. self.rear = new_node
    16. else:
    17. self.rear.next = new_node
    18. self.rear = new_node
    19. self.size += 1
    20. def dequeue(self):
    21. if self.front is None:
    22. print("Queue Underflow")
    23. return None
    24. data = self.front.data
    25. self.front = self.front.next
    26. if self.front is None:
    27. self.rear = None
    28. self.size -= 1
    29. return data
    30. def peek(self):
    31. if self.front is None:
    32. print("Queue is empty")
    33. return None
    34. return self.front.data
    35. def isEmpty(self):
    36. return self.front is None
    37. def size(self):
    38. return self.size
    39. ```

Применение очередей

Очереди используются в широком спектре приложений, включая:

  1. Планирование задач: Очереди используются для управления порядком выполнения задач в операционных системах и других системах.
  2. Обработка запросов: Очереди используются для обработки запросов к серверам и другим ресурсам.
  3. Моделирование: Очереди используются для моделирования реальных систем, таких как очереди в магазинах, банках и т.д.
  4. Поиск в ширину (BFS): Очереди используются для хранения информации о посещенных вершинах графа при поиске в ширину.
  5. Буферизация данных: Очереди используются для буферизации данных между производителем и потребителем.
  6. Системы обмена сообщениями: Очереди используются для асинхронной передачи сообщений между различными компонентами системы.

Примеры использования очереди

  1. Моделирование очереди в магазине:
    1. ```python
    2. import time
    3. import random
    4. class Customer:
    5. def __init__(self, id):
    6. self.id = id
    7. self.arrival_time = time.time()
    8. self.service_time = random.randint(2, 5)
    9. class StoreQueue:
    10. def __init__(self):
    11. self.queue = []
    12. self.customer_id = 1
    13. def add_customer(self):
    14. customer = Customer(self.customer_id)
    15. self.queue.append(customer)
    16. print(f"Customer {customer.id} arrived at {time.strftime('%H:%M:%S', time.localtime(customer.arrival_time))}")
    17. self.customer_id += 1
    18. def serve_customer(self):
    19. if self.queue:
    20. customer = self.queue.pop(0)
    21. print(f"Serving customer {customer.id}. Service time: {customer.service_time} seconds.")
    22. time.sleep(customer.service_time)
    23. print(f"Customer {customer.id} finished service.")
    24. else:
    25. print("No customers in the queue.")
    26. def run_simulation(self, num_customers=5):
    27. for _ in range(num_customers):
    28. self.add_customer()
    29. time.sleep(random.randint(1, 3)) # Simulate random arrival times
    30. while self.queue:
    31. self.serve_customer()
    32. store = StoreQueue()
    33. store.run_simulation()
    34. ```
  1. Задача о горячей картошке (Hot Potato):
    1. ```python
    2. def hot_potato(names, num):
    3. queue = list(names)
    4. while len(queue) > 1:
    5. for i in range(num):
    6. queue.append(queue.pop(0))
    7. eliminated = queue.pop(0)
    8. print(f"{eliminated} исключен.")
    9. return queue[0]
    10. names = ["Bill", "David", "Susan", "Jane", "Kent", "Brad"]
    11. winner = hot_potato(names, 7)
    12. print(f"Победитель: {winner}")
    13. ```

Преимущества и недостатки использования очередей

Преимущества:

  1. Справедливость: Элементы обслуживаются в порядке их поступления.
  2. Простота реализации: Очереди легко реализовать с использованием массивов или связных списков.
  3. Широкий спектр применения: Очереди используются в различных областях программирования.

Недостатки:

  1. Ограниченный доступ: Доступ к элементам очереди ограничен началом и концом очереди.
  2. Фиксированный размер (при реализации с использованием массива): При реализации очереди с использованием массива необходимо заранее определять его размер, что может быть ограничением в некоторых случаях.
  3. Необходимость сдвига элементов (при реализации с использованием линейной очереди): При удалении элемента из начала очереди необходимо сдвигать все последующие элементы на одну позицию влево, что может быть неэффективным при большом количестве элементов.

Понимание принципа FIFO и очередей является важным для разработки эффективного и надежного программного обеспечения.