`

java 实现undo和redo操作链表的一种实现

    博客分类:
  • java
 
阅读更多
今天在iteye论坛逛,发现有这么一道笔试题目:实现一个可以增加一个节点、删除某个区间的节点、修改某个节点、undo和redo的链表。
有个网友atomduan给这道题目的一种实现形式,现在我在他的代码上加了注释,利于理解。

import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

public class EditableLinkedList<T> {
	
	private LinkedList<T> primaryList = new LinkedList<T>();
	
	//快照列表
	private LinkedList<List> snapshotList = new LinkedList<List>();
	
	//上一次操作调用的方法
	private Method lastOperation;
	
	//上一次操作调用的方法参数
	private Object[] lastOperationArgs;
	
	//拍快照,每操作一次拍下快照
	private void takeSnapshot() {
		List<T> snapshot = new LinkedList<T>();
		for (T element : primaryList) {
			snapshot.add(element);
		}
		snapshotList.add(snapshot);
	}
	
	//从最新的快照恢复
	private void restoreFromSnapshot() {
		//pollLast()获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。
		List<T> snapshot = snapshotList.pollLast();  
		primaryList.clear();
		for (T element : snapshot) {
			primaryList.add(element);
		}
	}
	
	//设置上次操作
	private void setLastInvokedOperation(String methodName, Object... params) {
		try {
			this.lastOperation = this.getClass().
				getMethod(methodName, this.getParamTypes(params));
		} catch (Exception e) {
			if (setLastMethodParamsGeneric(methodName, params)==false){
				e.printStackTrace();
			}
		}
		this.lastOperationArgs = params;
	}
     
	//设置上一个方法的参数
	private boolean setLastMethodParamsGeneric(String methodName, Object... params) {
		Method[] methods = this.getClass().getMethods();
		for (int i=0; i<methods.length; i++) {
			if (this.isMethodMatch(methods[i], methodName, params)) {
				this.lastOperation = methods[i];
				return true;
			}
		}
		return false;
	}
	
	//判断方法是否匹配
	private boolean isMethodMatch(Method method, String methodName, Object... params){
		if (!method.getName().equalsIgnoreCase(methodName)) {
			return false;
		}
		Class<?>[] paramTypes = method.getParameterTypes();
		if (paramTypes.length != params.length) {
			return false;
		}
		for (int i=0; i<params.length; i++) {
			if (!paramTypes[i].isAssignableFrom(params[i].getClass())) {
				return false;
			}
		}
		return true;
	}
	
	//获取参数的类型
	private Class<?>[] getParamTypes(Object... params) {
		Class<?>[] paramTypes = new Class<?>[params.length];
		for (int i=0; i<params.length; i++) {
			paramTypes[i] = params[i].getClass(); 
		}
		return paramTypes;
	}
	
	//执行上一个方法
	private void invokeLastMethod() {
		try {
			this.lastOperation.invoke(this, this.lastOperationArgs);
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}
	
	//删除操作
	public void delete(Integer beginIndex, Integer endIndex) {
		//删除操作之前拍下快照
		this.takeSnapshot();
		for (int i=beginIndex; i<=endIndex; i++) {
			primaryList.remove(beginIndex);
		}
		this.setLastInvokedOperation("delete", beginIndex, endIndex);
	}
	
	//插入操作
	public void insert(T element, Integer index) {
		//插入操作之前拍下快照
		this.takeSnapshot();
		primaryList.add(index, element);
		this.setLastInvokedOperation("insert", element, index);
	}
	
	//修改操作
	public void modify(T element, Integer index) {
		//修改操作之前拍下快照
		this.takeSnapshot();
		primaryList.set(index, element);
		this.setLastInvokedOperation("modify", element, index);
	}
	
	//重做,取消复原
	public void redo() {
		//执行上次操作的方法
		this.invokeLastMethod();
	}
	
    //撤销
	public void undo() {
		//重最新的快照中恢复
		this.restoreFromSnapshot();
	}
	
	public String toString() {
		return this.primaryList.toString();
	}
	
	public static void main(String[] args) {
		EditableLinkedList<String> ell = new EditableLinkedList<String>();
		ell.insert("hey", 0);
		System.out.println(ell);
		ell.redo();
		System.out.println(ell);
		ell.undo();
		System.out.println(ell);
		ell.redo();
		System.out.println(ell);
		ell.undo();
		System.out.println(ell);
		ell.undo();
		System.out.println(ell);
	}
}

运行结果:
[hey]
[hey, hey]
[hey]
[hey, hey]
[hey]
[]
分享到:
评论

相关推荐

    2 万字 + 30 张图 | 细聊 MySQL undo log、redo log、binlog 有什么用?.doc

    在本文中,我们讨论了 MySQL 事务日志机制的原理和实现,包括 undo log、redo log 和 binlog 三种日志机制的作用和原理。我们还讨论了 MySQL 事务日志机制的应用场景,包括数据备份、主从复制和事务回滚等。

    栈.docx

    *.undo/redo 操作:栈可以用来实现 undo/redo 操作,通过将每个操作的状态压入栈中,然后通过出栈和恢复实现 undo/redo 操作。 栈是一种非常重要的数据结构,它具有简洁且节省空间的优点,广泛应用于各种计算机系统...

    数据结构线性表的链式表示和实现.pdf

    数据结构线性表的链式表示和实现 一、链式表示的基本概念 链式表示是一种数据结构,它使用链表来存储数据。链表是一种动态的数据结构,它由多个结点组成,每个结点包含了一个数据元素和一个指针,指向下一个结点。...

    InnoDB-undo-log与MVCC1

    InnoDB的undo log是数据库管理系统中用于实现事务回滚和多版本并发控制(MVCC)的关键机制。它是一种逻辑日志,与binlog不同,主要用于撤销事务对数据的修改。undo log通常存储在InnoDB的共享表空间内,以便在事务...

    java数据结构之java实现栈

    Java 数据结构之 Java ...* 实现 undo 和 redo 操作 结论 本文介绍了 Java 中使用数组实现栈的方法,包括栈的基本操作、实现原理和应用场景。栈是一种基础数据结构,掌握栈的实现和应用是 Java 开发者的必备技能。

    java 实现链栈存储的方法

    java 是一种流行的编程语言,下面我们将讲解如何使用 java 实现链栈存储的方法。 链栈是一种特殊的数据结构,它可以实现 Last-In-First-Out(后进先出)的特性,即最后入栈的元素将最先被取出。链栈可以用于解决...

    UndoRedo的简单实现

    `std::list`是一种双向链表,支持高效的插入和删除操作,这使得它非常适合用于存储和管理一系列操作记录。 具体实现时,我们需要创建两个`std::list`对象,一个用于存储需要撤销的行动(UndoStack),另一个用于...

    钣金激光切割加工CAD_CAM软件中撤消重做的实现.pdf

    每一个操作都被视为一个对象,为了便于这些操作对象的管理,建立了一个Undo/Redo管理类,并使用链表记录这些操作对象。这样,每一个操作都能被记录下来,以便在执行撤销或重做时能够恢复或重复。 该撤消重做功能的...

    java 数据结构中栈和队列的实例详解

    java 数据结构中栈和队列是两种重要的线性数据结构,都是在一个特定的范围的存储单元中的存储数据。与线性表相比,它们的插入和删除操作收到更多的约束和限定,又被称为限定性的线性表结构。栈是先进后出FILO,队列...

    数据结构栈的实验报告.doc

    栈有很多实际应用,如解析表达式、实现递归函数、实现Undo/Redo功能等。 五、实验环境和方法 实验环境:Windows xpVisual C++6.0 实验方法: (一)综合运用课本所学的知识,用不同的算法实现在不同的程序功能。...

    易语言编辑框的撤销重复功能

    "易语言编辑框的撤销重复功能"是指在易语言环境中,为编辑框添加了撤销(Undo)和重复(Redo)功能,这是一种常见于文本编辑器和IDE中的高级特性,允许用户取消最近的操作,并在需要时恢复它们。 撤销/重复功能的...

    InnoDB事务、锁、多版本分析

    InnoDB的多版本并发控制是通过ReadView和 undo/redo日志实现的。ReadView是每个事务用于判断数据可见性的视图,根据事务的开始时间,决定能看到哪些数据版本。聚簇索引和二级索引共同构建了多版本的数据结构,使得在...

    java底层技术面试必备基础知识.pdf(700+页)

    而当事务需要回滚时,则通过回滚日志(undo log)来实现。 ##### 2. 并发一致性问题 在多用户共享数据库的环境中,事务的并发执行可能会导致数据不一致的问题,常见的问题包括: - **丢失修改**:多个事务同时对...

    MySQL 核心引擎InnoDB-事务锁多版本分析

    在事务提交时,它会进行一系列操作,如记录undo日志和redo日志,数据持久化以及将脏页加入FlushList链表等。 在锁方面,InnoDB支持多种锁类型,包括事务锁(Lock)、页面锁(Latch)和互斥锁(Mutex)。事务锁主要...

    INNODB关键技术原理以及MYSQL常用规范

    INNODB存储引擎的事务机制是基于Undo Log和Redo Log的,事务特性包括原子性、一致性、隔离性和持久性(ACID)。 * Undo Log:在事务没提交之前,MYSQL会先记录更新前的数据到undo log日志文件里面,当事务回滚时...

    有赞2019校招前端笔试.docx

    栈是一种先进后出的数据结构,非常适合实现 undo/redo 功能。 第五个问题讨论了公开密钥加密算法,Alice 使用 Bob 的公钥对信息进行加密,Bob 使用自己的私钥对信息进行解密。这个问题可以使用公开密钥加密算法的...

    03 LineEdit.rar

    3. **文本编辑算法**:比如,实现撤销/重做功能时,需要记录并回溯一系列编辑操作,这可能需要用到文本编辑操作的抽象表示(如undo-redo操作树)和相应的算法。 4. **字符串匹配算法**:KMP算法、Boyer-Moore算法等...

    Lexi文档编辑器

    此外,考虑到文本编辑器的实时性,需要实现滚动、查找替换等操作,这就需要我们理解并应用数据结构,如链表、栈和队列等。 文件系统交互通常包括文件的读写操作。在 Python 中,可以使用内置的 `open()` 函数,结合...

    MFC编写简易文本编辑器

    5. ** undo/redo 无限历史**:通过链表或堆栈结构存储更长的历史记录。 通过以上步骤,我们可以构建一个基础的MFC文本编辑器,后续还可以根据需求进行功能扩展和性能优化。在实际开发过程中,理解和掌握MFC类库的...

    MYSQL面试题-20230927

    通过以上对BufferPool、B+树索引、Explain工具、MVCC、Redo Log、Undo Log以及Binlog的介绍,我们可以了解到MySQL InnoDB存储引擎在处理数据缓存、索引优化、事务控制等方面的技术细节和实现原理。这些知识点对于...

Global site tag (gtag.js) - Google Analytics