本文详细介绍了如何在自定义单向链表中高效移除所有指定元素实例。我们将分析现有移除方法的局限性,指出对象比较中`==`与`.equals()`的关键区别,并提供一个健壮的解决方案,通过维护`previous`和`current`指针遍历链表,正确处理头、尾及中间节点的删除,确保链表结构完整性并准确更新元素计数。
在深入探讨元素移除之前,我们首先回顾自定义LinkedList和LinearNode类的基本结构。
在提供的LinkedList类中,有几个与移除操作相关的方法:
在Java中,比较两个对象是否“相等”是一个常见的需求,但其含义可能因上下文而异。
示例:Employee类的equals方法实现建议
考虑到驱动类中employee对象被用于list.clear(b),如果希望根据courseName来移除员工,那么Employee类必须重写equals方法以包含courseName的比较逻辑。
public class employee {
private String number;
private String name;
private int years;
private String courseName;
// 构造函数
public employee(String number, String name, int years, String courseName) {
this.number = number;
this.name = name;
this.years = years;
this.courseName = courseName;
}
// Getter方法
public String getCourseName() {
return courseName;
}
// 其他getter/setter方法...
@Override
public boolean equals(Object obj) {
// 1. 检查是否为同一个对象引用
if (this == obj) {
return true;
}
// 2. 检查obj是否为null或类型不匹配
if (obj == null || getClass() != obj.getClass()) {
return false;
}
// 3. 将obj转换为employee类型
employee other = (employee) obj;
// 4. 比较关键属性(例如,如果只根据courseName判断相等)
// 注意:这里假设只根据courseName来判断两个employee对象是否“相等”
// 如果需要根据所有属性或特定组合属性判断,则需要修改比较逻辑
if (this.courseName == null) {
return other.courseName == null;
}
return this.courseName.equals(other.courseName);
// 如果需要比较所有属性,例如:
/*
return Objects.equals(number, other.number) &&
Objects.equals(name, other.name) &&
years == other.years &&
Objects.equals(courseName, other.courseName);
*/
}
@Override
public int hashCode() {
// 重写equals方法时通常也需要重写hashCode方法
// 这里简化为只使用courseName
return Objects.hash(courseName);
}
@Override
public String toString() {
return "Employee [number=" + number + ", name=" + name + ", years=" + years + ", courseName=" + courseName + "]";
}
}重要提示: employee类中的equals方法定义了两个employee对象何时被认为是相等的。如果希望list.clear(b)方法能够根据courseName移除所有匹配的员工,那么employee的equals方法必须实现基于courseName的比较逻辑。上述示例中,equals方法被修改为仅基于courseName进行比较。如果需要根据其他属性(如员工编号)进行比较,则需要相应调整equals方法的实现。
为了正确移除链表中所有与给定元素相等(通过.equals()方法判断)的实例,我们需要一个更健壮的clear方法。该方法将遍历链表,并使用previous和current两个指针来维护链表结构。
import java.util.Objects; // 用于employee类的equals和hashCode方法 // ... LinkedList类的其他代码 ... public class LinkedListimplements LinkedListADT { private int count; // the current number of elements in the list private LinearNode list; //pointer to the first eleme nt private LinearNode
last; //pointer to the last element // ... 构造函数、add、remove等方法 ... /** * 从链表中移除所有与给定元素相等的实例。 * * @param element 要移除的元素。 * @return 成功移除的元素数量。 */ public long clear(T element) { long removedCount = 0L; // 记录移除元素的数量 LinearNode current = this.list; LinearNode previous = null; // 指向当前节点的前一个节点 // 遍历链表 while (current != null) { // 使用Objects.equals()处理可能为null的元素,并进行内容比较 if (Objects.equals(current.getElement(), element)) { // 如果当前节点元素与目标元素相等,则移除当前节点 if (previous != null) { // 如果不是头节点,将前一个节点的next指向当前节点的next previous.setNext(current.getNext()); // 如果当前节点是尾节点,更新last指针 if (current.getNext() == null) { this.last = previous; } } else { // 如果是头节点,将list指针指向下一个节点 this.list = current.getNext(); // 如果链表现在为空,更新last指针 if (this.list == null) { this.last = null; } } // 减少链表元素计数 this.count--; // 增加移除计数 removedCount++; // 移除节点后,current不需要前进,因为previous已经跳过了它 // 下一个要检查的节点已经是current.getNext() // 但是在循环的最后current会更新到下一个节点,所以这里不需要额外操作 } else { // 如果当前节点元素不相等,则将previous指向current,然后current前进 previous = current; } // 移动到下一个节点 current = current.getNext(); } return removedCount; } }
在TrainingCourses驱动类中,调用list.clear(b)时,现在它将使用我们新实现的clear方法。确保employee类中的equals方法按照您的需求(例如,基于courseName)正确实现,这样clear方法才能根据您期望的条件移除元素。
public class TrainingCourses {
// ... 其他代码 ...
public void deleteCourses(){
// ... 获取用户输入的employee b ...
// 调用新的clear方法,它将移除所有匹配的员工
long removed = list.clear(b);
System.out.println("成功移除了 " + removed + " 名员工。");
}
// ... 其他代码 ...
}在自定义链表中移除所有指定元素实例是一个常见的操作,但需要注意以下几点:
通过遵循这些原则,您可以构建一个健壮且高效的自定义链表元素移除功能。