- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
因此,我有一个实现Iterable的类,以为其编写一组方法。他们中的大多数都很容易思考,但是,我在为类编写remove方法时遇到了麻烦。
import java.util.Iterator;
public class Bag<Item> implements Iterable<Item> {
private Item[] data = (Item[]) new Object[5];
// The size variable keeps track of how many items
private int size = 0;
public String toString() {
StringBuilder b = new StringBuilder("[");
for (Item i : this)
b.append(i + " ");
return b.toString() + "]";
}
public void expandArray() {
int capacity = data.length * 2;
Item[] newData = (Item[]) new Object[capacity];
for (int i = 0; i < data.length; i++)
newData[i] = data[i];
data = newData;
}
public boolean add(Item x) {
if (size == data.length)
expandArray();
data[size++] = x;
return true;
}
// return an Iterator for the bag
public Iterator<Item> iterator() {
return new BagIterator<Item>();
}
// Iterator class
public class BagIterator<Item> implements Iterator<Item> {
private int i = 0;
public boolean hasNext() {
return i < size;
}
public Item next() {
return (Item) data[i++];
}
}
public boolean contains(Item x) {
for (int i = 0; i < data.length; i++) {
if (data[i] == x)
return true;
}
return false;
}
public boolean addUnique(Item x) {
for (int i = 0; i < data.length; i++) {
if (data[i] == x)
return false;
}
this.size++;
this.add(x);
return true;
}
public boolean remove(Item x) {
Item lastItem = x; // holds x item
Item swap; // holds item to swap
int swapIndex; // holds index of item to swap
for (int i = 0; i < data.length; i++) {
if (data[i] == x) {
// Save the last item
lastItem = data[3];
// Save the swapped item
swap = data[i];
// Save the index of swapped item
swapIndex = i;
// move swap item to end of list
data[3] = swap;
// move last item to swap pos
data[swapIndex] = lastItem;
// remove last item in list
this.size--;
return true;
}
}
return false;
}
public boolean equals(Object o) {
Bag<Item> b = (Bag<Item>) o;
return false;
}
}
public class Main {
public static void main (String[] args) {
Bag<Integer> bag = new Bag<>();
bag.add(1);
bag.add(2);
bag.add(3);
bag.add(4);
System.out.println(bag); // [1, 2, 3, 4]
System.out.println(bag.remove(4)); // should remove 4 and return true **WORKING
System.out.println(bag.remove(1)); // should remove 1 and return true **WORKING
System.out.println(bag.remove(1)); // should NOT remove 1 and return false **NOT WORKING
System.out.println(bag); // [4 ]
}
}
最佳答案
不知何故,我第一次完全误读了你的问题;我知道现在您甚至没有实现Iterator.remove()
。 Iterable.remove()
也是棘手的,让我们谈谈!
首先,您可能不想直接实现Iterable
。它只允许您遍历一系列元素(并可以选择调用Iterator.remove()
),而没有别的。您的Bag
类可能应该实现Collection
(或扩展AbstractCollection
),这是大多数Java数据结构实现的常规接口(它指定.add()
,.remove()
,.size()
等)。
创建数据结构(例如bag)时要记住的关键是强制执行invariants。粗略地说,不变是关于数据结构或方法的行为的保证。例如,每次在空数据结构上调用.size()
时,它将返回0
。一旦调用.add()
,以后所有对.size()
的调用都将返回1
(直到您进一步修改数据结构)。这是不变的。看起来似乎很明显,但是随着数据结构变得越来越复杂,这些简单的保证使代码推理变得更加简单。
关于您的特定问题。首先,您的想法是将物品移到最后,这是一个很好的直觉。这比将其余元素复制到新索引中要有效得多。
您首先担心的是,Bag
的大小仍然相同,这实际上不是问题。由于递减size
,有效地删除了数组末尾的项目。您可以将其设置为null
以删除引用,但就正确性而言,它不是必需的。相反,您应该查看其他方法,例如contains()
,并确保它们尊重size
。您应该只查看小于size
的索引,而不是data.length
,因为size
和data.length
之间的值可能是垃圾。
关于比较两个Bag
的第二个问题是暴露另一个问题。您的类实际上没有提供将要对数组进行排序的不变性(再次有该词),因此在.remove()
期间对其进行重新排序不会使事情变得比以前更糟。问题是您的类不会覆盖.equals()
和.hashcode()
(您必须两者都不做),这意味着无论元素的顺序如何,都不能将两个Bag
实例视为等效的。如果打算比较Bag
,则需要正确实现这些方法。假设您要这样做,绝对是棘手的。一般而言,没有一种比较两个无序对象集合的有效方法-您唯一的选择是遍历两个集合的所有元素,直到您确认它们包含相同的元素。性能为O(n ^ 2)或二次方(即非常慢)。
您有两个基本选择;确保您的支持数组始终排序(这是不变的-在将对数组进行排序的每种方法的末尾),或者使用效率更高的数据结构进行相等性检查,例如Set
。两种选择都有权衡。正确地确保始终对数组进行排序非常棘手; Java的TreeMap
做到了这一点,大多数人认为这是他们永远不想自己重新实现的代码类型。使用Set
可让您有效地检查集合中是否存在某个元素,但这是以防止重复元素为代价的。 “袋子”数据结构通常允许重复,因此对于您的用例,使用Set
作为后备数据结构可能是不可接受的。使用一个Map<E, Integer>
值是一个计数将是可行的,但是要跟踪的工作量却更多。
但是,作为起点,标准的蛮力.equals()
实现可能就足够了。优秀软件工程的核心任务是避免过度优化。从可行的东西开始,然后使其变得更好,而不是尝试从一开始就使效率完全提高。
关于java - 为实现Iterable的类编写remove方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36854016/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!