返回

前中后队列的魅力:链表实现的奥秘

前端


算法解锁:前中后队列的设计与实现

前言

算法之旅的序幕就此拉开,欢迎踏入 LeetCode 的题海之滨。作为本次旅程的开篇,我们聚焦于一道看似简单却暗藏玄机的问题——设计前中后队列。它将考验我们对链表结构和算法策略的掌握程度。

1. 前中后队列的定义

前中后队列是一种特殊的数据结构,它包含三个队列:前队列、中队列和后队列。每个队列遵循先进先出的原则(FIFO)。前中后队列的核心特性如下:

  • 前队列: 从队首插入元素,从队首删除元素。
  • 中队列: 从队首插入元素,从队尾删除元素。
  • 后队列: 从队尾插入元素,从队尾删除元素。

2. 链表实现

为了构建前中后队列,链表是一种理想的数据结构。链表是一种线性数据结构,由一系列相互连接的节点组成,每个节点包含一个数据域和一个指向下一个节点的指针。

链表节点结构:

class Node {
    int data;
    Node next;
}

前中后队列实现:

class FrontMiddleBackQueue {
    private Node frontHead, middleHead, backHead, middleTail;

    public FrontMiddleBackQueue() {
        frontHead = middleHead = backHead = middleTail = null;
    }

    public void pushFront(int val) {
        Node newNode = new Node(val);
        newNode.next = frontHead;
        frontHead = newNode;
        updateMiddleHead();
    }

    public void pushMiddle(int val) {
        Node newNode = new Node(val);
        if (middleHead == null) {
            middleHead = middleTail = newNode;
        } else {
            middleTail.next = newNode;
            middleTail = newNode;
        }
    }

    public void pushBack(int val) {
        Node newNode = new Node(val);
        if (backHead == null) {
            backHead = newNode;
        } else {
            backHead.next = newNode;
        }
        backHead = newNode;
        updateMiddleTail();
    }

    public int popFront() {
        if (frontHead == null) {
            return -1;
        }
        int val = frontHead.data;
        frontHead = frontHead.next;
        updateMiddleHead();
        return val;
    }

    public int popMiddle() {
        if (middleHead == null) {
            return -1;
        }
        int val = middleHead.data;
        if (middleHead == middleTail) {
            middleHead = middleTail = null;
        } else {
            middleHead = middleHead.next;
            updateMiddleTail();
        }
        return val;
    }

    public int popBack() {
        if (backHead == null) {
            return -1;
        }
        int val = backHead.data;
        if (backHead == frontHead) {
            frontHead = middleHead = backHead = null;
        } else {
            Node prev = getPrevNode(backHead);
            prev.next = null;
            backHead = prev;
        }
        return val;
    }

    private void updateMiddleHead() {
        middleHead = frontHead;
        int count = 1;
        while (count < middleIndex()) {
            middleHead = middleHead.next;
            count++;
        }
    }

    private void updateMiddleTail() {
        middleTail = backHead;
        int count = 0;
        while (count < middleIndex()) {
            middleTail = middleTail.next;
            count++;
        }
    }

    private Node getPrevNode(Node node) {
        Node prev = null;
        Node cur = frontHead;
        while (cur != null && cur != node) {
            prev = cur;
            cur = cur.next;
        }
        return prev;
    }

    private int middleIndex() {
        int size = 0;
        Node cur = frontHead;
        while (cur != null) {
            cur = cur.next;
            size++;
        }
        if (size % 2 == 0) {
            return size / 2;
        } else {
            return size / 2 + 1;
        }
    }
}

3. 时间复杂度分析

操作 时间复杂度
pushFront O(1)
pushMiddle O(1)
pushBack O(1)
popFront O(1)
popMiddle O(1)
popBack O(1)

4. 总结

前中后队列的实现需要对链表结构和算法策略有深入的理解。通过巧妙地利用链表,我们可以有效地维护队列的先进先出特性。链表实现的时间复杂度为 O(1),这使前中后队列成为一种高效的数据结构。

算法之旅才刚刚开始,还有更多的挑战和收获等待着我们。让我们带着对算法的热情和求知的渴望继续前进,征服算法世界!