Java 实现阵列的撤消和重做

Java 实现阵列的撤消和重做,java,arrays,algorithm,collections,Java,Arrays,Algorithm,Collections,我在今天的Java采访中得到了这个问题 我必须实现一个集合,它是一个数组,并且具有只能在数组末尾执行的add和delete方法 除此之外,我还必须实现另外两种方法,即只能执行一次的undo和redo方法 例如: 设x是包含{1,5,7,9}的数组。 现在我在其中添加了{44,66,77},并使其成为{1,5,7,9,44,66,77} 现在当我撤销它时,数组应该删除{44,66,77}。如果我以后重做,它应该回到{1,5,7,9,44,66,77} 同样的删除 在复杂性和内存方面,实现这一目标的

我在今天的Java采访中得到了这个问题

我必须实现一个集合,它是一个数组,并且具有只能在数组末尾执行的
add
delete
方法

除此之外,我还必须实现另外两种方法,即只能执行一次的
undo
redo
方法

例如:

设x是包含
{1,5,7,9}的数组。

现在我在其中添加了
{44,66,77}
,并使其成为
{1,5,7,9,44,66,77}

现在当我撤销它时,数组应该删除
{44,66,77}
。如果我以后重做,它应该回到
{1,5,7,9,44,66,77}

同样的删除

在复杂性和内存方面,实现这一目标的最佳方法是什么

我对面试官的回答是:

  • 制作一个字符串字段,用于存储最后一个操作,即“添加”/“删除”
  • 以及一个hashmap,它将key存储为数组的索引,value存储为数组的索引值

  • 根据采访者的说法,这是一个完全不正确的解决方案。

    我一直在做一些研究,正如我所建议的,您可以注册进入数组的“事物”的数量,然后将其存储在某个地方。因此,当您执行“撤消”操作时,它会删除最后插入的对象

    因此,请这样想:

    容器中保存了数组中输入的项数=1,2,4,2

    数组={[x][x,x][x,x,x,x][x,x]}

    如果要删除最后一个操作,请从容器2中执行,并从数组中删除最后一个条目,这样您就可以:

    包含输入数组的项目数的容器=1,2,4

    数组={[x][x,x][x,x,x,x]}

    等等等等


    此外,您还可以查看一个有趣的模式,该模式提供了将对象恢复到其先前状态的功能。

    如果您希望使用最小内存:

  • 存储主阵列。它将包含数组中的所有条目
  • 存储一个映射(位图足以实现单个撤消/重做迭代。使用更复杂的映射类型来实现多级撤消/重做)以标记元素的状态-活动/新建/删除

  • 我能想到的一件事是拥有一个数组。大概是这样的:

    Actual Data = []
    Bitmap History = [[]]
    End Index = 0
    
    class SetUndoAction implements UndoAction {
        int index;
        Object oldValue;
    
        SetUndoAction(int index, Object oldValue) {
            this.index = index;
            this.oldValue = oldValue;
        }
    
        public void undo() {
            Object newValue = get(index);
            set(index, oldValue);
            oldValue = newValue;
        }
    }
    
    添加[4,5]

    Actual Data = [[4, 5]]
    Bitmap History = [ [00], [11] ]
    End Index= 1
    
    Actual Data = [[4, 5], [6, 7]]
    Bitmap History = [ [0000], [1100], [1111] ]
    End Index = 2
    
    Actual Data = [[4, 5], [6, 7], [8, 9]]
    Bitmap History = [ [000000], [110000], [111100], [111111] ]
    End Index = 3
    
    添加[6,7]

    Actual Data = [[4, 5]]
    Bitmap History = [ [00], [11] ]
    End Index= 1
    
    Actual Data = [[4, 5], [6, 7]]
    Bitmap History = [ [0000], [1100], [1111] ]
    End Index = 2
    
    Actual Data = [[4, 5], [6, 7], [8, 9]]
    Bitmap History = [ [000000], [110000], [111100], [111111] ]
    End Index = 3
    
    添加[8,9]

    Actual Data = [[4, 5]]
    Bitmap History = [ [00], [11] ]
    End Index= 1
    
    Actual Data = [[4, 5], [6, 7]]
    Bitmap History = [ [0000], [1100], [1111] ]
    End Index = 2
    
    Actual Data = [[4, 5], [6, 7], [8, 9]]
    Bitmap History = [ [000000], [110000], [111100], [111111] ]
    End Index = 3
    
    在索引0处添加[1,2]

    Actual Data = [[1,2], [4,5], [6,7], [8,9]]
    Bitmap History = [ [00000000], [00110000], [00111100], [00111111], [11111111] ]
    End Index = 4
    
    删除9

    Actual Data = [[1,2], [4,5], [6,7], [8,9]]
    Bitmap History = [ [00000000], [00110000], [00111100], [00111111], [11111111], [11111110] ]
    
    删除8

    Actual Data = [[1,2], [4,5], [6,7], [8,9]]
    Bitmap History = [ [00000000], [00110000], [00111100], [00111111], [11111111], [11111110], [11111100] ]
    
    在末尾添加10

    Actual Data = [[1,2], [4,5], [6,7], [8,9], [10]]
    Bitmap History = [ [000000000], [001100000], [001111000], [001111110], [111111110], [111111100], [111111000], [111111001] ]
    End Index = 7
    
    应撤消三次→ 结束索引=4→ 使用位图历史[11111111 0]展平

    Flattened Data = [1,2,4,5,6,7,8,9]
    
    有一个名为flatte()的方法,该方法使用位图历史记录中的数据获取数组的内容并从中创建单个数组

    现在,当您想要撤消时,您所做的只是减小结束索引值。要重做,只需增加结束索引值。展平方法将负责显示实际数据数组中的正确元素


    删除操作在位图历史记录中插入一个新条目,并关闭该数字的标志。

    要么我误解了这个问题,要么人们想得太多。这个问题有很多限制,因此:

    • 当前内容的数组
    • 最后删除的项目的额外数组(需要撤消删除/重做添加)
    • 一个变量表示数组的上一个长度(需要撤消添加/重做删除)
    • 最后一个操作的一个枚举变量(添加/删除)
    • 一个布尔值表示是否刚刚完成撤消

    然后在每个不同的操作上更新这些。不需要堆栈或任何东西,因为不需要多次撤消/重做。

    我将这样实现它:

    Actual Data = []
    Bitmap History = [[]]
    End Index = 0
    
    class SetUndoAction implements UndoAction {
        int index;
        Object oldValue;
    
        SetUndoAction(int index, Object oldValue) {
            this.index = index;
            this.oldValue = oldValue;
        }
    
        public void undo() {
            Object newValue = get(index);
            set(index, oldValue);
            oldValue = newValue;
        }
    }
    
    执行的操作可以作为字符串保存在数组/向量中。在阵列上的每个操作上,都可以存储有关操作的信息。在数组上的每次撤消/重做时,将从操作数组中提取一个值,如果撤消,则执行计数器操作;如果重做,则执行相同的操作;执行操作后,将更新操作数组中的值或指针

    假设您有一个数组arr和操作数组optarptr,它将指向optar中的最后一个元素

    将5添加到数组中 arr{5}optArr{“添加5”}ptr=0

    Actual Data = [[1,2], [4,5], [6,7], [8,9]]
    Bitmap History = [ [00000000], [00110000], [00111100], [00111111], [11111111] ]
    End Index = 4
    
    将9添加到数组中 arr{5,9}optArr{“添加5”,“添加9”}ptr=1

    将7添加到数组中 arr{5,9,7}optArr{“添加5”、“添加9”、“添加7”}ptr=2

    从数组中删除9 arr{5,7}optArr{“添加5”、“添加9”、“添加7”、“删除9”}ptr=3

    对于“撤消”命令 值为“删除9”现在将执行计数器操作(“添加9”)

    对于redo命令
    值为“删除9”将被执行。

    我将这样解决它。基本上,将有三个列表

    • 包含实际值的列表
    • 使用
      命令的实例撤消列表
    • 包含
      命令
      接口实例的重做列表(可选,解释如下)

    将有两个
    Command
    实现:
    AddCommand
    RemoveCommand

    • add()
      上,创建了
      AddCommand
      的新实例,并将其添加到撤消列表中。然后我们调用此命令的
      do()
      ,它修改实际值并存储添加项的
      索引
    • remove()
      上,创建了
      RemoveCommand
      的新实例,并将其添加到撤消列表中。然后我们调用这个命令的
      do()
      ,它修改实际值和电阻