惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Schneier on Security
P
Proofpoint News Feed
Apple Machine Learning Research
Apple Machine Learning Research
WordPress大学
WordPress大学
博客园 - Franky
V
V2EX
爱范儿
爱范儿
J
Java Code Geeks
小众软件
小众软件
Last Week in AI
Last Week in AI
The Cloudflare Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Hugging Face - Blog
Hugging Face - Blog
T
The Blog of Author Tim Ferriss
酷 壳 – CoolShell
酷 壳 – CoolShell
The Register - Security
The Register - Security
GbyAI
GbyAI
Vercel News
Vercel News
Y
Y Combinator Blog
腾讯CDC
F
Fortinet All Blogs
I
InfoQ
N
Netflix TechBlog - Medium
B
Blog RSS Feed
D
Docker
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
量子位
博客园 - 司徒正美
阮一峰的网络日志
阮一峰的网络日志
The GitHub Blog
The GitHub Blog
Microsoft Security Blog
Microsoft Security Blog
V
Visual Studio Blog
博客园 - 三生石上(FineUI控件)
宝玉的分享
宝玉的分享
Blog — PlanetScale
Blog — PlanetScale
H
Help Net Security
云风的 BLOG
云风的 BLOG
A
About on SuperTechFans
Scott Helme
Scott Helme
T
Tor Project blog
U
Unit 42
Google Online Security Blog
Google Online Security Blog
PCI Perspectives
PCI Perspectives
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
NISL@THU
NISL@THU
D
Darknet – Hacking Tools, Hacker News & Cyber Security
aimingoo的专栏
aimingoo的专栏
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Stack Overflow Blog
Stack Overflow Blog
Security Archives - TechRepublic
Security Archives - TechRepublic

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Implementando uma pilha a partir de uma fila
Jefferson Qu · 2026-05-19 · via DEV Community

Jefferson Quesado

Em uma conversa despretenciosa com o Leandro Proença no LinkedIn, mencionei que dá pra implementar pilha usando apenas uma fila.

Bem, vamos fazer isso? Primeiro, vamos definir exatamente o que é "implementar uma estrutura X com uma estrutura Y", então vamos pro caso mais trivial que é implementar uma fila usando duas pilhas, então vamos implementar uma pilha usando apenas uma fila.

Nota importante aqui, muitos desses resultados e das estratégias usadas são decorrentes de conversas que já tivemos aqui no Computaria, como por exemplo:

Definindo pilhas e filas

Já definimos antes essas estruturas, né? Como em Criando filas e pilhas "apenas" com funções em java, mas ali tinha algumas limitações diferentes (como a questão dos efeitos colaterais) que me levaram a decisões de design... diferentes... do que se encontraria em um código Java selvagem em seu habitat natural.

No caso, aqui vamos usar algo mais parecido com as estruturas de dados que foram usadas para percorrer os grafos em Meu take sobre o algoritmo de Dijkstra:

  • push(element: T) => void
  • pop() => T
  • empty() => boolean

Aqui tanto pilha como fila vão seguir esse mesmo shape: um container que eu posso inserir objetos, recuperar objetos de lá de dentro e verificar se está vazio.

Uma fila com duas pilhas

Bem, aqui a implementação básica é a pilha, então vou precisar instanciar ela. Vou fazer de modo bem simples: um ArrayList que eu insiro e removo do final:

public class Pilha<T> {
    private final ArrayList<T> elementos = new ArrayList<>();

    public void push(T t) {
        elementos.addLast(t);
    }

    public T pop() {
        return elementos.removeLast();
    }

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

Enter fullscreen mode Exit fullscreen mode

Ok, agora vamos fazer a partir disso uma Fila<T>. Eu posso simplesmente quando chegar um novo elemento colocar na pilha? Posso, só preciso tomar cuidado na hora de remover o elemento: não posso remover com um simples pop, preciso garantir que seja o primeiro a entrar!

O jeito clássico de fazer isso é usando uma pilha secundária: ao chegar uma requisição de pop, eu recoloco os elementos da pilha principal na pilha secundária. O último elemento removido da pilha principal equivale à parte da frente da fila, portanto precisa ser retornado. Após isso, só colocar de volta no lugar os elementos que foram deslocados (em tese daria para otimizar para muitos pop seguidos, mas aqui o foco não é otimização):

public class Fila<T> {
    private final Pilha<T> elementos = new Pilha<>();
    private final Pilha<T> secundaria = new Pilha<>();

    public void push(T t) {
        elementos.push(t);
    }

    public T pop() {
        while (!elementos.empty()) {
            secundaria.push(elementos.pop());
        }
        final var v = secundaria.pop();
        while (!secundaria.empty()) {
            elementos.push(secundaria.pop());
        }
        return v;
    }

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

Enter fullscreen mode Exit fullscreen mode

Existe uma outra maneira de imoplementar isso, que seria pegar o elemento antes do fim. Vai sacando os valores e, ao detectar o fim, retornar o elemento encontrado:

public class Fila<T> {
    private final Pilha<T> elementos = new Pilha<>();
    private final Pilha<T> secundaria = new Pilha<>();

    public void push(T t) {
        elementos.push(t);
    }

    public T pop() {
        while (true) {
            final var candidato = elementos.pop();
            if (elementos.empty()) {
                // devolve os elementos de volta
                while (!secundaria.empty()) {
                    elementos.push(secundaria.pop());
                }
                return candidato;
            }
            secundaria.push(candidato);
        }
    }

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

Enter fullscreen mode Exit fullscreen mode

Uma pilha com duas filas

Bem, já que estamos trocando de empurrar no começo pro empurrar no fim, será que dá para pegar o exato mesmo algoritmo de duas pilhas simulando uma fila e fazer duas filas simulando uma pilha? Na real... dá sim!

Não importa o como vai ser implementada a fila em si, apenas que siga a convenção de comportamento. Então, podemos até assumir que vamos usar a fila desenvolvida na seção anterior.

Com isso fora de preoucupação, vamos seguir o mesmo formato de algoritmo:

public class Pilha<T> {
    private final Fila<T> elementos = new Fila<>();
    private final Fila<T> secundaria = new Fila<>();

    public void push(T t) {
        elementos.push(t);
    }

    public T pop() {
        while (true) {
            final var candidato = elementos.pop();
            if (elementos.empty()) {
                // devolve os elementos de volta
                while (!secundaria.empty()) {
                    elementos.push(secundaria.pop());
                }
                return candidato;
            }
            secundaria.push(candidato);
        }
    }

    public boolean empty() {
        return elementos.empty();
    }
}

Enter fullscreen mode Exit fullscreen mode

Uma pilha com uma fila

Vamos pensar aqui qual o objetivo de se usar a fila secundária? Vamos fazer um desenho de como está sendo a questão do uso dessas coisas?

  • eu diminuo a fila principal
  • se eu cheguei no final da fila principal, o último elemento removido precisa ser retornado
  • se eu não cheguei no final da fila principal, preciso guardar o que foi removido
  • após detectar o momento do retorno, tudo que foi removido preciso ser inserido de volta na fila principal

Ou seja, eu preciso de:

  • indicador de fim
  • um buffer para restaurar a fila

E se... eu conseguir fazer isso usando apenas uma única fila? Bem, pra isso eu preciso trabalhar com a fila de modo... especial... No lugar da fila ter apenas elementos do tipo T, preciso que ela tenha um elemento tal que não seja do tipo T que eu possa diferenciar. As operações que eu faço via pilha são todas em cima de T, a API externa não muda. Mas internamente eu preciso de um novo elemento que seja incompatível com os elementos que estou inserindo. Algo semelhante foi usado para poder transformar função parcial em função total no artigo Criando mapas "apenas" com funções em java.

A minha primeira ideia seria fazer com que o backbone da implementação de Pilha<T> fosse Fila<Object> e eu iria inserir forçosamente um new Object(), que ficaria marcado no momento da criação como "elemento de diferenciação". Mas então lembrei que eu posso fazer algo semelhante a um sum-type usando sealed interface (exploro mais isso no artigo Usando Java moderno para fazer aritmética de Peano):

sealed interface Elemento<V> {
    record Demarcador<V>() implements Elemento<V> {}
    record Container<V>(V v) implements Elemento<V> {}
}

Enter fullscreen mode Exit fullscreen mode

Agora vou usar uma instância Demarcador para indicar que cheguei no final da fila. Se eu tenho um final forte, isso significa que eu posso simplesmente readicionar os elementos que eu tinha após o final da fila. Logo, isso significa que manter uma estrutura secundária apenas por buffer de elementos de torna desnecessário.

Agora, ao dar um pop, preciso verificar se o elemento é o demarcador. Se for, preciso retornar o elemento que foi sacado logo antes dele. Se não for um demarcador, preciso guardar o penúltimo elemento de volta na fila, e reservar o elemento que acabei de sacar para a próxima iteração:

public class Pilha<T> {

    private sealed interface Elemento<V> {
        record Demarcador<V>() implements Elemento<V> {}
        record Container<V>(V v) implements Elemento<V> {}
    }

    private final Fila<Elemento<T>> elementos = new Fila<>();

    public void push(T t) {
        elementos.push(new Elemento.Container<>(t));
    }

    public T pop() {
        elementos.push(new Elemento.Demarcador<>());
        Elemento.Container<T> penultimo = null;
        while (true) {
            final var candidato = elementos.pop();
            if (candidato instanceof Elemento.Container<T> anotherValue) {
                if (penultimo != null) {
                    elementos.push(penultimo);
                }
                penultimo = anotherValue;
            } else {
                return penultimo.v();
            }
        }
    }

    public boolean empty() {
        return elementos.empty();
    }
}

Enter fullscreen mode Exit fullscreen mode

Como teste, adicionei 4 elementos e depois saquei até o esgotamento da pilha:

final var p = new Pilha<String>();
p.push("a");
p.push("b");
p.push("c");
p.push("d");
while (!p.empty()) {
    System.out.println(p.pop());
}

Enter fullscreen mode Exit fullscreen mode

Note algumas coisas interessantes:

  • o elemento Demarcador só é inserido durante o processo de pop, e o processo de pop só termina após sacar o Demarcador
  • eu só preciso fazer a reinserção dos elementos após o segundo saque

Essa observação do "segundo saque" me leva a uma implementação alternativa, que incondicionalmente faz o primeiro saque e reserva o valor, antes mesmo de sequer cogitar inserir o demarcador. A ideia é:

  • saca o elemento
  • se estiver vazio, retorna o elemento
  • se não estiver vazio, reserva esse elemento
  • insere o demarcador
  • continue sacando próximos elementos
  • se o elemento sacado for demarcador, retorne o elemento reservado
  • se não, insira o elemento reservado de volta e reserve o elemento sacado
public T pop() {
    var reservado = (Elemento.Container<T>) elementos.pop();
    if (elementos.empty()) {
        return reservado.v();
    }
    elementos.push(new Elemento.Demarcador<>());
    while (true) {
        final var candidato = elementos.pop();
        if (candidato instanceof Elemento.Container<T> anotherValue) {
            elementos.push(reservado);
            reservado = anotherValue;
        } else {
            return reservado.v();
        }
    }
}

Enter fullscreen mode Exit fullscreen mode