Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Циклическая очередь

Циклическая очередь — это линейная структура данных, работающая по принципу FIFO (первым пришёл — первым ушёл), в которой хвост соединён с головой, образуя кольцо. Также известна как «кольцевой буфер».

Преимущество циклической очереди в том, что она позволяет повторно использовать освободившееся место. В обычной очереди после заполнения вставка нового элемента невозможна, даже если в начале есть свободное место. Циклическая очередь позволяет использовать эти ячейки для хранения новых значений.

Properties

  • de_queue O(1)
  • en_queue O(1)
#![allow(unused)]
fn main() {
use std::{
    alloc::{self, Layout},
    ptr,
};

pub struct CircularQueue<T> {
    write_index: usize,
    read_index: usize,
    cap: usize,
    len: usize,
    data: Box<[T]>,
}

impl<T> CircularQueue<T> {
    pub fn new(cap: usize) -> Self {
        let data = unsafe {
            let data_ptr = alloc::alloc(Layout::array::<T>(cap).unwrap()) as *mut T;
            Box::from_raw(ptr::slice_from_raw_parts_mut(data_ptr, cap))
        };
        Self {
            write_index: 0,
            read_index: 0,
            cap,
            len: 0,
            data,
        }
    }

    /**
     * add value to CircularQueue
     * return true if success, false if queue is full
     */
    pub fn en_queue(&mut self, value: T) -> bool {
        if self.is_full() {
            false
        } else {
            self.data[self.write_index] = value;
            self.write_index = (self.write_index + 1) % self.cap;
            self.len += 1;
            true
        }
    }

    /**
     * remove value from CircularQueue
     * return true if success, false if queue is full
     */
    pub fn de_queue(&mut self) -> bool {
        if self.is_empty() {
            false
        } else {
            self.read_index = (self.read_index + 1) % self.cap;
            self.len -= 1;
            true
        }
    }

    /**
     * get front value
     */
    pub fn front(&self) -> Option<&T> {
        if self.is_empty() {
            None
        } else {
            Some(&self.data[self.read_index])
        }
    }

    /**
     * get tail value
     */
    pub fn rear(&self) -> Option<&T> {
        if self.is_empty() {
            None
        } else if self.write_index == 0 {
            Some(&self.data[self.cap - 1])
        } else {
            Some(&self.data[self.write_index - 1])
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len == 0
    }

    pub fn is_full(&self) -> bool {
        self.cap == self.len
    }
}

#[cfg(test)]
mod tests {
    use std::result;

    use super::*;

    #[test]
    fn test_en_queue() {
        let mut circular_queue = CircularQueue::new(100);
        for i in 0..100 {
            let result = circular_queue.en_queue(i);
            assert!(result);
        }
        let result = circular_queue.en_queue(100);
        assert!(!result);
    }

    #[test]
    fn test_de_queue() {
        let mut circular_queue = CircularQueue::new(100);
        for i in 0..200 {
            circular_queue.en_queue(i);
        }

        for _ in 0..100 {
            let result = circular_queue.de_queue();
            assert!(result);
        }

        let result = circular_queue.de_queue();
        assert!(!result);
    }

    #[test]
    fn test_circular_queue_order() {
        let mut circular_queue = CircularQueue::new(3);

        for i in 1..4 {
            circular_queue.en_queue(i);
        }

        circular_queue.en_queue(4);

        let result = circular_queue.rear();
        assert_eq!(result, Some(&3));

        assert!(circular_queue.is_full());

        circular_queue.de_queue();

        circular_queue.en_queue(4);
        let result = circular_queue.front();
        assert_eq!(result, Some(&2));

        let result = circular_queue.rear();
        assert_eq!(result, Some(&4))
    }
}
}