What is the Best Data Structure for Undo/Redo , (ctrl+z , ctrl+y) ?
Before few days our teacher said that the stack is the best for undo , but i am thinking about double-linked list ..
is there any another data structure do our purpose in a better quality ? or one of those two lead our purpose & which one of them ?
PS : if there is better data structure then explain it using (oop) -java preferred- & thanks for help
put all the actions in a stack for multi level undo. and in case of redo make another stack.this stack will keep all the commands you have undone.so when you perform an undo command you pop undo stack and push the action into redo stack.You do same thing into redo .when you pop a redo action put it into undo stack
Undo/Redo are stack based (first in, last out) operation from principle, so you need some kind of stack based architecture to store actions.
With that being said, the way how you stack behaviour can differ based on other requirements of your application. Usual way is to have stack backed by array - you keep current index of last element and you add (remove) new stuff elements to at that index and increase (decrease) ot accordingly
But you can also implement this first-in-last-out behaviour in a different way, for example double linked list - you will keep reference to the last element of the list and either add new to the end (and update this reference) or remove last element (and also update the reference to the new last). Giving yourself stack-like behaviour
EDIT:
For redo you keep separate stack, where you push commands whenever you undo them, so you can use it later (pop from redo stack, do it, push to undo stack)
It is important to clear redo stack when you push new (e.g. not from redo stack) command to undo stack
Related
In my macOS App with Mixed Objective-C/Swift, in the Xcode memory graph, there are instances of dispatch_group leaked:
I am a bit familiar with GCD and I use it in my project, but I don't use dispatch_groups explicitly in my code. I have thought that it could be some indirect usage of it when I call other GCD APIs like dispatch_async. I was wondering if there is somebody that can help me track this issue. Thanks for your attention.
In order to diagnose this, you want to know (a) what is keeping a strong reference to them; and (b) where these objects were instantiated. Unfortunately, unlike many objects, dispatch groups might not tell you much about the former (though your memory addresses suggest that there might be some object keeping a reference to them), but we can use the “Malloc Stack” feature to answer the latter.
So, edit your scheme (“Product” » “Scheme” » “Edit Scheme” or press command-<) and temporarily turn on this feature:
You can then click on the object in question and the panel on the right might show you illuminating stack information about where the object was allocated:
Now, in this case, in viewDidLoad I manually instantiated six dispatch groups, performed an enter, but not a leave, which is why these objects are still in memory. This is a common source of dispatch groups lingering in memory.
As you look at the stack trace, focus first on entries in your codebase (in white, rather than gray, in the stack trace). And if you click on your code in the stack trace, it will even jump you to the relevant line of code. But even if it is not in your code, often the stack trace will give you insights where these dispatch groups were created, and you can start your research there.
And remember, when you are done with your diagnostics, make sure to turn off the “Malloc Stack” feature.
Suppose this is a mathematical application that manipulates waveforms. User opens a waveform file, and edits it.
Now user amplifies waveform using the application toolbox. Amplification may take a long time. Then they undo it. And then they redo it again.
For redo, how should the application behave?
Replace result of amplification that was performed before and was held in memory internally by the application.
Re-run the time-consuming amplification procedure again?
This problem expands to every functionality.
Thanks :-)
Undo-redo actions are typically implemented using a stack of commands and the position of the last executed command. After an undo, you move that position one step backward without removing the last command of the stack (now one past the last executed command).
Whether you store data along with your commands is up to you. However, in the situation you describe, for the undo to work, you need to either reverse the last command perfectly (and you may not be able to), or keep the previous state in memory. So keeping the next state, after the amplification, should not cost you anything in this particular case. However, you do need to properly discard it if the user does not redo that command.
As #eddiewould pointed out in a comment, a command can be inherently destructive (so unreversible) and allowing to undo it (by keeping the previous state) can be unfeasable, for example because of memory restrictions. In such a case, you should inform the user beforehand that going back will be impossible.
I have several questions about multi-paxos
will each instance has it's own proposal Number and accepted ballot and accepted value ? or all the instance share with the same
proposal number ,after one is finished ,then anther one start?
if all the instance share with the same proposal number ,Consider the below condition, server A sends a proposal ,and the acceptor returns the accepted instanceId which might be greater or less than the proposal'instanceid ,then what will proposal do? use that instanceId and it's value for accept phase? then increase it'own instanceId ,waiting for next round ,then re-proposal with it own value? if so , when is the previous accepted value removed,because if it's not removed ,the acceptor will return this intanceId and value again,then it seems it is a loop
Multi-Paxos has a vague description so two persons may build two different systems based on it and in a context of one system the answer is "no," and in the context of another it's "yes."
Approach #1 - "No"
Mindset: Paxos is a two-phase protocol for building write-once registers. Multi-Paxos is a technique how to create a log on top of them.
One of the possible ways to build a log is
Create an array of completely independent write-once registers and initialize the first one with an initial value.
On new record we should:
A) Guess an index (X) of a vacant register and try to write a dummy record here (if it's already used then pick a register with a higher index and retry).
B) Start writing dummy records to every register with smaller than X index until we find a register filled with a non-dummy record.
C) Calculate a new record based on it (e.g., a record may have an ordinal, and we can use it to calculate an ordinal of the new record; since some registers are filled with dummy records the ordinals aren't equal to index) and write it to the X+1 register. In case of a conflict, we should restart the procedure from step A).
To read the log we should start writing dummy values from the first record, and on each conflict, we should increment index and retry until the write is succeeded which would indicate that the log's end is reached.
Of course, there is a lot of overhead in this approach, so please treat it just like a top-level overview what Multi-Paxos is.
The log is a powerful concept, and we can use it as a recipe for building distributed state machines - just think of each record as an update command. Unfortunately, in some cases, there is also a lot of overhead. For example, if you want to build a key/value storage and you care only about the current value than you don't need history and probably need to implement garbage collection to remove past versions from the log to optimize storage costs.
Approach #2 - "Yes"
Mindset: rewritable register as a heavily optimized version of Multi-Paxos.
If you start with the described approach with an application to the creation of key/value storage and then iterate in other to get rid of overhead, e.g., by doing garbage collection on the fly then eventually you may come up with an idea how to update the write-once register to be rewritable.
In that case, each instance uses the same ballot numbers just because all the instances are collapsed into one rewritable instance.
I described this approach in the How Paxos Works post and implemented it in the Gryadka project with 500-lines of JavaScript. Also, the idea behind it was independently checked with TLA+ by Greg Rogers and Tobias Schottdorf.
Part of my project is to write a text editor that is used for typing some rules, compiling my application and running it. Writing compiler was end and release beta version. In the final version we must add undo and redo to the text editor. I use a file and save it periodically for the text editor. How to design undo and redo to my text editor? What is changed in the structure of persistent of file?
You can model your actions as commands, that you keep in two stacks. One for undo, another for redo. You can compose your commands to create more high-level commands, like when you want to undo the actions of a macro, for example; or if you want to group individual keystrokes of a single word, or phrase, in one action.
Each action in your editor (or a redo action) generates a new undo command that goes into the undo stack (and also clears the redo stack). Each undo action generates the corresponding redo command that goes into the redo stack.
You can also, as mentioned in the comments by derekerdmann, combine both undo and redo commands into one type of command, that knows how to undo and redo its action.
There are basically two good ways to go about it:
the "Command" design pattern
using only OO over immutable objects, where everything is just immutable objects made of immutable objects made themselves of immutable objects (this is less common but wonderfully elegant when done correctly)
The advantage of using OO over immutable objects over the naive command or the naive undo/redo is that you don't need to think much about it: no need to "undo" the effect of an action and no need to "replay" all the commands. All you need is a pointer to a huge list of immutable objects.
Because objects are immutable all the "states" can be incredibly lightweight because you can cache/reuse most objects in any state.
"OO over immutable objects" is a pure jewel. Probably not gonna become mainstream before another 10 years that said ; )
P.S: doing OO over immutable objects also amazingly simplifies concurrent programming.
If you don't want anything fancy, you can just add an UndoManager. Your Document will fire an UndoableEdit every time you add or remove text. To undo and redo each change, simply call those methods in UndoManager.
The downside of this is UndoManager adds a new edit each time the user types something in, so typing "apple" will leave you with 5 edits, undoable one at a time. For my text editor, I wrote a wrapper for edits that stores the time it was made in addition to text change and offset, as well as an UndoableEditListener that concatenates new edits to previous ones if there is only a short period of time between them (0.5 seconds works well for me).
This works well for general editting, but causes problems when a massive replace is done. If you had a document with 5000 instances of "apple" and you wanted to replace this with "orange", you'd end up with 5000 edits all storing "apple", "orange" and an offset. To lower the amount of memory used, I've treated this as a separate case to ordinary edits and am instead storing "apple", "orange" and an array of 5000 offsets. I haven't gotten around to applying this yet, but I know that it'll cause some headaches when multiple strings match the search condition (eg. case insensitive search, regex search).
Wow, what a conicidence - I have literally in the last hour implemented undo/redo in my WYSIWYG text editor:
The basic idea is to either save the entire contents of the text editor in an array, or the difference between the last edit.
Update this array at significant points, i.e. every few character (check the length of the content each keypress, if its more than say 20 characters different then make a save point). Also at changes in styling (if rich text), adding images (if it allows this), pasting text, etc. You also need a pointer(just an int variable) to point at which item in the array is the current state of the editor)
Make the array have a set length. Each time you add a save point, add it to the start of the array, and move all of the other data points down by one. (the last item in the array will be forgotten once you have so many save points)
When the user presses the undo button, check to see if the current contents of the editor are the same as the latest save (if they are not, then the user has made changes since the last save point, so save the current contents of the editor (so it can be redo-ed), make the editor equal to the last save point, and make the pointer variable = 1 (2nd item in array ). If they are they same, then no changes have been made since the last save point, so you need to undo to the point before that. To do this, increment the pointer value + 1, and make the contents of the editor = the value of pointer.
To redo simply decrease the pointer value by 1 and load the contents of the array (make sure to check if you have reached the end of the array).
If the user makes edits after undoing, then move the pointed value array cell up to cell 0, and move the rest up by the same amount (you dont want to redo to other stuff once they've made different edits).
One other major catch point - make sure you only add a save point if the contents of the text editor have actually changed (otherwise you get duplicate save points and it will seem like undo is not doing anything to the user.
I can't help you with java specifics, but I'm happy to answer any other questions you have,
Nico
You can do it in two ways:
keep a list of editor states and a pointer in the list; undo moves the pointer back and restores the state there, redo moves forward instead, doing something throws away everything beyond the pointer and inserts the state as the new top element;
do not keep states, but actions, which requires that for every action you have a counteraction to undo the effects of that action
In my (diagram) editor, there are four levels of state changes:
action fragments: these are part of a larger action and not separately undoable or redoable
(e.g. moving the mouse)
actions: one or more action fragments that form a meaningful change which can be undone or redone,
but which are not reflected in the edited document as changed on disk
(e.g. selecting elements)
document changes: one or more actions that change the edited document as it would be saved to disk
(e.g. changing, adding or deleting elements)
document saves: the present state of the document is explicitly saved to disk - at this point my editor throws away the undo history, so you can't undo past a save
This is a job for the command pattern.
Here is a snippet that shows how SWT supports Undo/Redo operations. Take it as practical example (or use it directly, if your editor is based on SWT):
SWT Undo Redo
Read a book Design Patterns: Elements of Reusable Object-Oriented Software. As far as I remember, there is a pretty good example.
It seems like three ways to approach detecting unsaved changes in a text/image/data file might be to:
Update a boolean flag every time the user makes a change or saves, which would result in a lot of unnecessary updates.
Keep a cached copy of the original file and diff the two every time a save operation needs to be checked.
Keep a stack of all past operations and push/pop operations as needed, resulting in a lot of extra memory usage.
In general, how do commercial applications detect whether unsaved changes exist and what are the advantages/disadvantages of each approach? I ran into this issue while writing a custom application that has special saving behavior and would like to know if there is a known best practice.
As long as you need an undo/redo system, you need that stack of past operations. To detect in wich state the document is, an item of the stack is set to be the 'saved state'. Current stack node is not that item, the document is changed.
You can see an example of this in Qt QUndoStack( http://doc.qt.nokia.com/stable/qundostack.html ) and its isClean() and setClean()
For proposition 1, updating a boolean is not something problematic and take little time.
This depends on the features you want and the size/format of the files, I guess.
The first option is the simplest, and it gives you just what you want with minial overhead.
The second option has the advantage that you can detect when changes have been manually reverted, so that there is no real change after all (although that probably doesn't happen all too often). On the other hand it is much more costly to make a diff just to check if anything was modified. You probably don't want to do that everytime the user presses a key.
The third option gives the ability to provide an undo-history. You could limit the number of items in that history by grouping changes together that were made consecutively (without moving the cursor in between), or something like that.