代码随想录 Day8 栈(FILO)与队列(FIFO) LeetCode T232 用栈实现队列 LeetCodeT225 用队列实现栈

 题目详细思路来自于:代码随想录 (programmercarl.com)

栈和队列都是大家不陌生的数据结构,我们之前的栈和队列一般是用数组或链表来实现的 ,

这里我们给出实现方式,用于帮助更好的理解.

1.用链表实现栈 

/* 基于链表实现的栈 */
class LinkedListStack {
private ListNode stackPeek; // 将头节点作为栈顶
    private int stkSize = 0; // 栈的长度
public LinkedListStack() {
    stackPeek = null;
}
/* 获取栈的长度 */
public int size() {
    return stkSize;
}
/* 判断栈是否为空 */
public boolean isEmpty() {
    return size() == 0;
}
/* 入栈 */
public void push(int num) {
    ListNode node = new ListNode(num);
    node.next = stackPeek;
    stackPeek = node;
    stkSize++;
}
/* 出栈 */
public int pop() {
    int num = peek();
    stackPeek = stackPeek.next;
    stkSize--;
    return num;
}
/* 访问栈顶元素 */
public int peek() {
    if (size() == 0)
        throw new IndexOutOfBoundsException();
    return stackPeek.val;
}
/* 将 List 转化为 Array 并返回 */
public int[] toArray() {
    ListNode node = stackPeek;
    int[] res = new int[size()];
    for (int i = res.length - 1; i >= 0; i--) {
        res[i] = node.val;
        node = node.next;
        }
    return res;
    }
}

 2.用数组实现栈

class ArrayStack {
    private ArrayList<Integer> stack;
    public ArrayStack() {
// 初始化列表(动态数组)
        stack = new ArrayList<>();
}
/* 获取栈的长度 */
public int size() {
    return stack.size();
}
/* 判断栈是否为空 */
public boolean isEmpty() {
    return size() == 0;
}
/* 入栈 */
public void push(int num) {
    stack.add(num);
}
/* 出栈 */
public int pop() {
    if (isEmpty())
        throw new IndexOutOfBoundsException();
    return stack.remove(size() - 1);
}
/* 访问栈顶元素 */
public int peek() {
    if (isEmpty())
        throw new IndexOutOfBoundsException();
    return stack.get(size() - 1);
}
/* 将 List 转化为 Array 并返回 */
public Object[] toArray() {
    return stack.toArray();
    }
}

 3.两种实现的优缺点

3.1 用数组实现栈的优缺点

在基于数组的实现中,入栈和出栈操作都是在预先分配好的连续内存中进行,具有很好的缓存本地性,因此效率较高。然而,如果入栈时超出数组容量,会触发扩容机制,导致该次入栈操作的时间复杂度变为 𝑂(𝑛).

3.2 用链表实现栈的优缺点

在链表实现中,链表的扩容非常灵活,不存在上述数组扩容时效率降低的问题。但是,入栈操作需要初始化节点对象并修改指针,因此效率相对较低。不过,如果入栈元素本身就是节点对象,那么可以省去初始化步骤,从而提高效率。

4. 用链表实现队列

class LinkedListQueue {
    private ListNode front, rear; // 头节点 front ,尾节点 rear
    private int queSize = 0;
public LinkedListQueue() {
    front = null;
    rear = null;
}
/* 获取队列的长度 */
public int size() {
    return queSize;
}
/* 判断队列是否为空 */
public boolean isEmpty() {
    return size() == 0;
}
/* 入队 */
public void push(int num) {
// 尾节点后添加 num
    ListNode node = new ListNode(num);
// 如果队列为空,则令头、尾节点都指向该节点
    if (front == null) {
        front = node;
        rear = node;
// 如果队列不为空,则将该节点添加到尾节点后
        } else {
        rear.next = node;
        rear = node;
        }
    queSize++;
}
/* 出队 */
public int pop() {
    int num = peek();
// 删除头节点
    front = front.next;
    queSize--;
    return num;
}
/* 访问队首元素 */
public int peek() {
    if (size() == 0)
        throw new IndexOutOfBoundsException();
    return front.val;
}
/* 将链表转化为 Array 并返回 */
public int[] toArray() {
    ListNode node = front;
    int[] res = new int[size()];
    for (int i = 0; i < res.length; i++) {
        res[i] = node.val;
        node = node.next;
        }
    return res;
    }
}

5.用数组实现队列

你可能会发现一个问题:在不断进行入队和出队的过程中, front 和 rear 都在向右移动, 当它们到达数组尾部时就无法继续移动了。为解决此问题,我们可以将数组视为首尾相接的“环形数组”。对于环形数组,我们需要让 front 或 rear 在越过数组尾部时,直接回到数组头部继续遍历。这种周期性规律可以通过“取余操作”来实现

/* 基于环形数组实现的队列 */
class ArrayQueue {
    private int[] nums; // 用于存储队列元素的数组
    private int front; // 队首指针,指向队首元素
    private int queSize; // 队列长度
public ArrayQueue(int capacity) {
    nums = new int[capacity];
    front = queSize = 0;
}
/* 获取队列的容量 */
public int capacity() {
    return nums.length;
}
/* 获取队列的长度 */
public int size() {
    return queSize;
}
/* 判断队列是否为空 */
public boolean isEmpty() {
    return queSize == 0;
}
/* 入队 */
public void push(int num) {
    if (queSize == capacity()) {
        System.out.println(" 队列已满");
        return;
}
// 计算尾指针,指向队尾索引 + 1
// 通过取余操作,实现 rear 越过数组尾部后回到头部
    int rear = (front + queSize) % capacity();
// 将 num 添加至队尾
    nums[rear] = num;
    queSize++;
}
/* 出队 */
public int pop() {
    int num = peek();
// 队首指针向后移动一位,若越过尾部则返回到数组头部
    front = (front + 1) % capacity();
    queSize--;
    return num;
}
/* 访问队首元素 */
public int peek() {
    if (isEmpty())
        throw new IndexOutOfBoundsException();
        return nums[front];
}
/* 返回数组 */
public int[] toArray() {
// 仅转换有效长度范围内的列表元素
    int[] res = new int[queSize];
    for (int i = 0, j = front; i < queSize; i++, j++) {
        res[i] = nums[j % capacity()];
        }
        return res;
    }
}

LeetCode T232 用栈实现队列

题目链接:

232. 用栈实现队列 - 力扣(LeetCode)

题目思路:

我们这里就要用两个栈来实现队列,一个是stackOut,一个是stackIn,in栈负责将要入队的添加进来,但是这时候我们发现出栈的话会和队列的出队顺序相反,所以我们再入栈一次,这样出栈的顺序就颠倒过来啦,也完美的实现队列的基本功能.

注:一定要将In栈的全部元素一起push进Out栈,否则顺序可能会发生变化,这样就影响了正常的出栈功能.

题目代码:

class MyQueue {
    Stack<Integer> stackIn;
    Stack<Integer> stackOut;

    public MyQueue() {
        stackIn = new Stack<>();
        stackOut = new Stack<>();

    }
    
    public void push(int x) {
        stackIn.push(x);

    }
    
    public int pop() {
        downStackIn();
        return stackOut.pop();
       

    }
    
    public int peek() {
        downStackIn();
        return stackOut.peek();

    }
    
    public boolean empty() {
        downStackIn();
        return stackOut.isEmpty();

    }
    public void downStackIn()
    {
        while(!stackOut.isEmpty())
        {
            return;
        }
        while(!stackIn.isEmpty())
        {
            stackOut.push(stackIn.pop());
        }
    }
}

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue obj = new MyQueue();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.peek();
 * boolean param_4 = obj.empty();
 */

LeetCode T225 用队列实现栈

题目链接:225. 用队列实现栈 - 力扣(LeetCode)

题目思路:

这里我们同样可以用和上一题同样的思路实现,但是为了更有挑战性,我们决定用一个队列来实现栈,假设我们入队元素是123,此时我们需要的出队元素应该是3,那么我们该如何操作呢,其实,我们只需要让前两个元素重新入队,这样第一个出队的元素就是3了,其实就是前size()-1个元素重新入队,就实现了出栈的操作

这里我使用的是deque,这个类可以实现两头的操作,就是比queue多了两头操作的一些方法.

题目代码:

class MyStack {
    Deque<Integer> que1;

    public MyStack() {
        que1 = new ArrayDeque<>();

    }
    
    public void push(int x) {
        que1.addLast(x);

    }
    
    public int pop() {
        int tmp = que1.size()-1;
        while(tmp>0)
        {
            que1.addLast(que1.peekFirst());
            que1.pollFirst();
            tmp--;
        }
        return que1.pollFirst();

    }
    
    public int top() {
        return que1.peekLast();

    }
    
    public boolean empty() {
        return que1.isEmpty();

    }
}

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack obj = new MyStack();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.top();
 * boolean param_4 = obj.empty();
 */

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值