计算机撤销操作的定义、存储数据及实现结构相关技术咨询
Great questions about undo operations—let’s break this down clearly, like we’re chatting through a coffee break!
At its core, undo is your digital "take-back button"—it lets you revert the system to the state it was in before your last (or recent) action. Think of it as hitting rewind on your last edit, move, or deletion.
To make this work, the system needs to store specific data about each action:
- Action type: What exactly did you do? (e.g., "deleted 5 characters", "moved a layer 10px right", "changed font size to 14pt")
- Affected target: Which part of the system was modified? (e.g., the text selection from position 20 to 25, the layer named "Background", cell B3 in a spreadsheet)
- State snapshot or delta: Either a full snapshot of the target before the action, or just the difference (delta) between the before and after states. Deltas are more memory-efficient—for example, instead of saving the entire document after every keystroke, just save the character you typed and where it was inserted.
- Order marker: A timestamp or sequence number to keep track of the order of actions, so the system knows which one to revert first.
Short answer: Yes, almost always.
Here’s why: Undo follows a Last-In-First-Out (LIFO) pattern. If you do Action A → Action B → Action C, pressing Ctrl+Z should undo C first, then B, then A. That’s exactly how a stack works—you push each new action onto the stack as you perform it, and when you hit undo, you pop the top (most recent) action off the stack and revert it.
Before you even press Ctrl+Z, the stack is already populated with your history of actions. The shortcut just triggers the "pop and revert" step. This is the standard implementation in nearly all software—from text editors like Notepad to design tools like Photoshop.
Absolutely! While stacks are the go-to for basic undo, other structures come in handy when you need more flexibility (like supporting redo, or branching workflows):
- Doubly Linked List: Perfect if you want to support both undo (
Ctrl+Z) and redo (Ctrl+Y). A doubly linked list lets you traverse forward and backward through action history. When you undo, you move to the previous node; when you redo, you jump back to the next one. This avoids needing a separate "redo stack" (which is what some stack-based implementations use) and makes it easier to manage a continuous history. - Linear Array (Log-Based): For simpler apps, you can store all actions in an array with a "current state" pointer. Undo moves the pointer left one position, redo moves it right. This is super easy to implement and works well for small-scale tools (like a simple todo app editor). You can even optimize it by merging consecutive similar actions (e.g., typing 10 characters in a row can be stored as one action instead of 10 separate ones).
- Tree Structure: Useful for apps where users might explore branching workflows—like CAD software or game level editors. For example, if you make a change to a design, then experiment with two different variations, a tree can store each branch of actions. You can then undo back to the original state and switch to a different branch whenever you want.
- Command Objects + Hybrid Structures: This is more of a design pattern paired with a data structure, but worth mentioning. Each action is wrapped in a "command" object that knows how to execute and undo itself. You can store these command objects in a stack, linked list, or array depending on your needs. This approach keeps your code clean and flexible—you can swap out the underlying data structure without rewriting all your undo logic.
Hope this clears up all your questions about how undo works under the hood!
内容的提问来源于stack exchange,提问作者DuZhentong

