目录

1.使用固定大小的数组实现ADT bag 包

  1.1 一组核心方法

  1.2 实现核心方法

   1.3 让实现安全

  1.4 测试核心方法

  1.5 实现更多的方法

  1.6 删除项的方法

  1.7 测试

  1.8 发现总结

2.使用可变大小的数组实现ADT包

  2.1 可变大小数组

  2.2 包的新实现

  2.3 使用数组实现ADT包的优缺点

1. 使用固定大小的数组实现ADT bag包

1.1 一组核心方法

  基于数组实现的ADT包ArrayBag,实现接口BagInterface,接口中定义了泛型T,在ArrayBag的定义中也用到了这个泛型。对于定义难懂的类(ArrayBag)有不少方法,不应该定义整个类,然后试图去测试它。而是定义一组核心方法(core mehod来实现并测试这些方法,然后再继续定义中的其他部分。(可以集中注意力,简化任务)。核心方法:这样的方法应该是类的重要目的,且允许合理的测试。有时称一组核心方法为核心组(core group)。

  对于Bag这样的集合,添加元素add方法是一个基本操作,如果add不成功,remove无从谈起。所以add方法去核心方法之一。测试add,需要能看见Bag内容的方法toArray,也是核心方法之一。构造方法也是基本的,另外,核心方法可能调用的任何方法也是核心组的一部分。比如,add需要判断是否bag已满isArrayFull。

  核心方法:(在这些核心方法能正确工作之前,先不实现其余方法)

  • 构造方法
  • public boolean add(T newEntry)
  • public T[] toArray()
  • private boolean isArrayFull()

  注:像add和remove这样能改变集合结构的方法,可能是与实现最紧密的方法。一般,这类方法的定义应该先于类中的其他方法。但因为add正确之前不能remove,所以将remove实现放在add完成后且进行充分测试后进行。

  程序设计技巧:当定义一个类时,实现并测试一组核心方法。从向对象集合添加对象及与之相关的方法开始。

1.2 实现核心方法

  数据域:对象数组,容量(默认容量或用户提供)

private final T[] bag;

private int numberOfEntries;

private static final int DEFAULT_CAPACITY = 25;

  加入类ArrayBag的UML表示:

  程序设计技巧:终态数组

  通过声明bag是类ArrayBag的一个终态数据成员,可知变量bag中的引用不能改,但是数据元素bag[0]等可改,但是要防止客户直接修改bag元素,以防数组内容受到恶意毁坏。

  构造方法:

  注意:

数组bag的泛型问题:

bag = new T[capacity]; // syntax error 分配数组时不能使用泛型

---> 转为object:

bag = new Object[capacity]; // imcompatible types不能将object数组赋给T型数组,两个类型不兼容 ----> 转型

bag = (T[])new Object[capacity]; // 编译警告,编译想保证将数组中的每项从类型object转为T都安全,有问题语句前写注释使编译忽略这个警告:@SuppressWarning(“unchecked”),该注释只能放在方法定义或变量声明之前 ---> 找个中间变量再声明一次

// The cast is safe because the new array contains null entries.

@SuppressWarning(“unchecked”)

T[] tempBag = (T[]) new Object[capacity];

bag = tempBag;

  注:禁止编译警告

  要禁止编译程序给出的未检查转型警告,可以在标记的语句之前写

  @SuppressWarning(“unchecked”)

  注意,这条命令只能放在方法定义或变量声明之前。应该包含一条注释,对禁止编译程序警告做出解释。

  类的框架:

/*** A class of bags whose entries are stored in a fixed-size array.* @author Administrator** @param <T>*/
public final class ArrayBag<T> implements BagInterface<T> {
private final T[] bag;
private int numberOfEntries;
private static final int DEFAULT_CAPACITY = 25;/*** Creates an empty bag whose initial capacity is 25.*/
public ArrayBag() {
this(DEFAULT_CAPACITY);
} // end default constructor/*** Creats an empty bag having a given initial capacity.* @param capacity: The integer capacity desired.*/
public ArrayBag(int capacity) {
// The cast is safe because the new array contains null entries.
@SuppressWarnings("unchecked")
T[] tempBag = (T[])new Object[capacity]; // Unchecked entries.
bag = tempBag;
numberOfEntries = 0;
} // end constructor/*** Gets the current number of entries in this bag.* @return: The integer number of entries currently in the bag.*/
@Override
public int getCurrentSize() {
// TODO Auto-generated method stub
return 0;
} // end getCurrentSize/*** Sees whether this bag is empty.* @return: True if the bag is empty, or false if not.*/
@Override
public boolean isEmpty() {
// TODO Auto-generated method stub
return false;
} // end isEmpty/*** Adds a new entry to this bag.* @param newEntry: The object to be added as a new entry.* @return: True if the addition is successful, or false if not.*/
@Override
public boolean add(T newEntry) {
// TODO Auto-generated method stub
return false;
} // end add/*** Removes one unspecified entry from this bag, if possible.* @return: Either the removed entry, if the removel was successful, or null.*/
@Override
public T remove() {
// TODO Auto-generated method stub
return null;
} // end remove/*** Removes one occurrence of a given entry from this bag, if possible.* @param anEntry: The entry to be removed.* @return: True if the removal was successful, or false if not.*/
@Override
public boolean remove(T anEntry) {
// TODO Auto-generated method stub
return false;
} // end remove/*** Removes all entries from this bag.*/
@Override
public void clear() {
// TODO Auto-generated method stub
} // end clear/*** Counts the number of times a given entry appears in this bag.* @param anEntry: The entry to counted.* @return: The number of times anEntry appears in the bag.*/
@Override
public int getFrequencyOf(T anEntry) {
// TODO Auto-generated method stub
return 0;
} // end getFrequencyOf/*** Tests whether this bag contains a given entry.* @param anEntry: The entry to locate.* @return: True if the bag contains anEntry, or false if not.*/
@Override
public boolean contains(T anEntry) {
// TODO Auto-generated method stub
return false;
} // end contains/*** Retrieves all entries that are in this bag.* @return: A newly allocated array of all the entries in the bag.*          Note: If the bag is empty, the returned array is empty.*/
@Override
public T[] toArray() {
// TODO Auto-generated method stub
return null;
} // end toArray// Returns true if the arraybag is full, or false if not.
private boolean isArrayFull() {
return numberOfEntries == 0;
} // end isArrayFull
} // end class ArrayBag

  程序设计技巧:当定义实现接口的类时,从接口中复制它们来添加类中公有方法的注释和头。使用这种方式,方便在实现时检查每个方法的规格说明。另外,维护代码的人也容易访问这些规格说明。

设计决策:当数组中装了一部分数据时,包的项应该放在数组的哪些位置

添加第一个项:数组中第一个,下标为0;

项是否连续:关于计划中的实现方案,必须确定某些事实或断言,以便每个方法的动作不会对其他方法产生不利。(toArray必须知道add将项放在哪里)(remove需要保证项连续吗?)

  方法add:如果包满了,则不添加,返回false;否则,将新元素添加到最后一个元素后面。

/*** Adds a new entry to this bag.* @param newEntry: The object to be added as a new entry.* @return: True if the addition is successful, or false if not.*/
@Override
public boolean add(T newEntry) {if(isArrayFull()) {return false;}else {// Assertion : result is true herebag[numberOfEntries++] = newEntry;return true;} // end if
} // end add    

  方法isArrayFull:包中项数与包容量相等时,包满返回true。

// Returns true if the arraybag is full, or false if not.
private boolean isArrayFull() {return numberOfEntries >= bag.length;
} // end isArrayFull

   方法toArray:获取包中的项,将它们返回到客户新分配的数组内。分配数组处理与构造方法相同。

/*** Retrieves all entries that are in this bag.* @return: A newly allocated array of all the entries in the bag.*          Note: If the bag is empty, the returned array is empty.*/
@Override
public T[] toArray() {// The cast is safe because the new array contains null entries.@SuppressWarnings("unchecked")T[] result = (T[])new Object[numberOfEntries]; //         Unchecked castfor(int i = 0; i < numberOfEntries; i++) {result[i] = bag[i];} // end forreturn result;
} // end toArray

1.3 让实现安全

 程序中检查可能出现的错误来练习有安全机制的程序设计(fail-safe programming)。安全可靠程序设计(safe and secure programming)通过验证输入给方法的数据和参数的合法性,消除方法的副作用,对客户和使用者的行为不做任何假设。

安全说明:保护ADT实现的完整性

两个问题:

  • 若构造方法没有完全执行,可能发生什么?完成初始化之前抛异常,入侵者捕获异常或错误,试图使用部分初始化的对象;
  • 客户试图创建一个容量超出给出范围的包,会发生什么?

如果这两个动作可能会导致问题,则必须阻止。

增加两个数据域:

private boolean initialized = false;
private static final int MAX_CAPACITY = 10000;

修改构造方法:

  判断客户参数和最大容量,大于抛出异常

  内存不足小于等于最大容量,系统是否能够分配成功?错误OutOfMemoryError黑客捕获这个异常,使用部分初始化的数据 ---> 利用initialized的状态判断是否执行方法

public ArrayBag(int capacity) {if(capacity <= MAX_CAPACITY) {// The cast is safe because the new array contains null entries.@SuppressWarnings("unchecked")T[] tempBag = (T[])new Object[capacity]; // Unchecked entries.bag = tempBag;numberOfEntries = 0;initialized = true;                      // Last action
    }else {throw new IllegalStateException("Attempt to create a bag whose "+ "capacity exceeds allowed maximum.");}
} // end constructor

  方法如何利用intialized变量:任何方法执行前都要确保数据域initialized的值为真。若为假,方法可以抛出一个异常。

public boolean add(T newEntry) {if(initialized) {boolean result = true;if(isArrayFull()) {result = false;}else {// Assertion : result is true herebag[numberOfEntries++] = newEntry;} // end ifreturn result;}else {throw new SecurityException("ArrayBag object is not initialized properly.");}
} // end add                    

  多个方法都要判断initialized,所以包装为方法:

// Throws an exception if this ovject is not initialized.
private void checkInitialized() {if(!initialized) {throw new SecurityException("ArrayBag object is not initialized properly.");}
} // end checkInitializedpublic boolean add(T newEntry) {checkInitialized();boolean result = true;if(isArrayFull()) {result = false;}else {// Assertion : result is true herebag[numberOfEntries++] = newEntry;} // end ifreturn result;
} // end addpublic T[] toArray() {checkInitialized();// The cast is safe because the new array contains null entries.@SuppressWarnings("unchecked")T[] result = (T[])new Object[numberOfEntries]; // Unchecked castfor(int i = 0; i < numberOfEntries; i++) {result[i] = bag[i];} // end forreturn result;
} // end toArray        

安全说明:

  • 将类的大多数数据域声明为私有的,如果不是全部。任何公有数据域都应该是静态和终态的,且有常量值;
  • 避免那些掩盖代码安全性的所谓聪明的逻辑;
  • 避免重复代码。相反,将这样的代码封装为一个可供其他方法调用的私有方法;
  • 当构造方法调用一个方法时,确保这个方法不能被重写。

  安全说明:终态类(ArrayBag是一个终态类final class,不会被继承,确保程序员不能继承来改变它的行为,比非终态类安全)

1.4 测试核心方法

  准备。已经实现三个核心方法,进行测试。其他需要实现的方法设为存根(stub),即一个不完整定义的方法。仅需要让语法检查器通过即可,return一个哑值,Boolean返回false,对象返回null,void方法为空方法体。如果想在测试程序中调用存根,应该显示一条信息来报告它被调用过。

  测试程序。(默认容量和超容量)

/*** A test of the constructors and the methods add and toArray,* as defined in the first draft of the class ArrayBag.* @author Administrator**/
public class ArrayBagDemo1 {public static void main(String[] args) {// Adding to an initially empty bag with sufficient capacitySystem.out.println("Testing an initially empty bag with the capacity to hold at least 6 strings:");BagInterface<String> aBag = new ArrayBag<>();String[] contentsBag1 = {"A", "B", "A", "D", "B", "C"};testAdd(aBag, contentsBag1);System.out.println("\nTesting an initially empty bag that will be filled to capacity:");aBag = new ArrayBag<>(7);String[] contentsOfBag2 = {"A", "B", "A", "C", "B", "C", "D", "another string"};testAdd(aBag, contentsOfBag2);} // end main// Tests the method add.public static void testAdd(BagInterface<String> aBag, String[] content) {System.out.println("Adding the following " + content.length + " strings to the bag: ");for(int index = 0; index < content.length; index++) {if(aBag.add(content[index])) {System.out.print(content[index] + " ");}else {System.out.print("\nUnable to add " + content[index] + " to the bag.");}} // end for
        System.out.println();displayBag(aBag);} // end testAdd// Tests the method thArray while displaying the bag.private static void displayBag(BagInterface<String> aBag) {System.out.println("The bag contains the following string(s):");Object[] bagArray = aBag.toArray();for(int index = 0; index < bagArray.length; index++) {System.out.print(bagArray[index] + " ");} // end for
        System.out.println();} // end displayBag
} // end ArrayBagDemo1

output:

Testing an initially empty bag with the capacity to hold at least 6 strings:

Adding the following 6 strings to the bag:

A B A D B C

The bag contains the following string(s):

A B A D B C

Testing an initially empty bag that will be filled to capacity:

Adding the following 8 strings to the bag:

A B A C B C D

Unable to add another string to the bag.

The bag contains the following string(s):

A B A C B C D

  程序设计技巧:方法的全貌测试还应该包括实参取值范围在合理范围内外的情况。

1.5 实现更多的方法

  方法isEmpty和getCurrentSize

  可以更早的定义它们,而不是为它们写存根。

public int getCurrentSize() {return numberOfEntries;
} // end getCurrentSizepublic boolean isEmpty() {return numberOfEntries == 0;
} // end isEmpty

  方法getFrequencyOf.(比较对象使用equals)

public int getFrequencyOf(T anEntry) {checkInitialization();int count = 0;for(int index = 0; index < numberOfEntries; index++) {if(bag[index].equals(anEntry)) {count++;} // end if} // end forreturn count;
} // end getFrequencyOf

  方法contains。

public boolean contains(T anEntry) {checkInitialization();boolean found = false;for(int index = 0; index < numberOfEntries; index++) {if(bag[index].equals(anEntry)) {found = true;break;}}return found;
} // end contains    

  测试:

public class ArrayBagDemo2 {public static void main(String[] args) {BagInterface<String> aBag = new ArrayBag<>();boolean created = aBag.isEmpty();System.out.println(created);aBag.add("wang");aBag.add("pu");aBag.add("wang");int size = aBag.getCurrentSize();System.out.println(size);System.out.println(aBag.contains("pu"));System.out.println(aBag.contains("he"));int count = aBag.getFrequencyOf("wang");System.out.println(count);}}

output:

true

3

true

false

2

1.6 删除项的方法

  方法clear(remove方法将调用checkInitialization,所以clear不需要显式地调用它)

public void clear() {while(!isEmpty()) {remove();}} // end clear

  删除不确定项remove。只要bag不空,就删除一个项并将项返回

public T remove() {checkInitialization();T temp = null;if(numberOfEntries > 0) {temp = bag[numberOfEntries - 1];bag[numberOfEntries - 1] = null;numberOfEntries--;} // end ifreturn temp;
} // end remove

  安全说明:将数组元素bag[numberOfEntries-1]设置为null,标记被删除对象可进行垃圾回收,并防止恶意代码来访问它。

  安全说明:在正确计数后更新计数器。删除数组最后一项后才将numberOfEntries减1,虽然刚开始减1会避免重复,但时间上微不足道的节省不值得冒太早减小计数器带来的不安全风险。

  删除给定项,remove。多次只删除第一次,删除后需要将该位置补上,因为不需要维护包中项的具体次序,所以只需要将最后一项移过来即可

public boolean remove(T anEntry) {checkInitialization();boolean result = false;if(numberOfEntries > 0) {for(int index = 0; index < numberOfEntries; index++) {if(bag[index].equals(anEntry)) {bag[index] = bag[numberOfEntries - 1];bag[numberOfEntries - 1] = null;numberOfEntries--;result = true;break;} // if} // end for} // end ifreturn false;} // end remove

  删除最后一项和remove相同,抽出共同部分removeEntry

// Removes and returns the entry at a given index within the array bag.// If no such entry exists, return null.// Preconditions: 0 <= givenIndex < numberOfEntries;//                checkInitialization has been called.private T removeEntry(int givenIndex) {T result = null;if (!isEmpty() && (givenIndex >= 0)) {result = bag[givenIndex];                       // Entry to removebag[givenIndex] = bag[numberOfEntries - 1];     // Replace entry with last entrybag[numberOfEntries - 1] = null;                // Remove last entrynumberOfEntries--;} // end ifreturn result;
} // end removeEntry

  此时remove

public T remove() {checkInitialization();T result = removeEntry(numberOfEntries - 1);return result;} // end removepublic boolean remove(T anEntry) {checkInitialization();int index = getIndexOf(anEntry);T result = removeEntry(index);return anEntry.equals(result);} // end remove

  需要索引函数,返回项的位置索引

// Locates a given entry within the array bag.// Returns the index of the entry, if bocated, or -1 otherwise.private int getIndexOf(T anEntry) {int getIndex = -1;if (numberOfEntries > 0) {for (int index = 0; index < numberOfEntries; index++) {if (bag[index].equals(anEntry)) {getIndex = index;break;} // if} // end for} // end ifreturn getIndex;} // end getIndexOf/* 正向思考private int getIndexOf(T anEntry) {int where = -1;boolean stillLooking = true;int index = 0;while (stillLooking && (index < numberOfEntries)){if (anEntry.equals(bag[index])){stillLooking = false;where = index;} // end ifindex++;} // end whilereturn where;} // end getIndexOf*/

  利用getIndexOf方法修改contains方法需要索引函数,返回项的位置索引

public boolean contains(T anEntry) {checkInitialization();return getIndexOf(anEntry) > -1;} // end contains

 因为已经修改了contains,所以需要再次测试。

 设计决策:什么方法应该调用checkInitialization?

  可以在直接涉及数组bag的每个方法都调用,不过更灵活的是,私有方法getIndexOf和removeEntry直接访问bag,但它们不调用,为什么?若调用,则在共有方法中被调两次,所以规定在共有方法中调用,并为这两个私有方法添加一个前置条件来说明checkInitialization必须要先调用(只给实现者和维护者使用)。私有方法只实现一个已定的任务,不再为第二任务负责。

  程序设计技巧:即使可能已经有了方法的正确定义,但如果想到了一个更好的实现,也不要犹豫地取修改它。肯定要再次测试方法!

1.7 测试

/*** A demostration of the class ArrayBag* @author Administrator**/
public class ArrayBagDemo {public static void main(String[] args) {String[] contentsOfBag = {"A", "A", "B", "A", "C", "A"};// Tests on an empty bagBagInterface<String> aBag = new ArrayBag<>(contentsOfBag.length);System.out.println("Testing an initially empty bag:");testIsEmpty(aBag, true);String[] testStrings1 = {"", "B"};testFrequency(aBag, testStrings1);testContains(aBag, testStrings1);testRemove(aBag, testStrings1);// Adding stringsSystem.out.println("Adding " + contentsOfBag.length + " strings to an initially empty bag "+ "with the capacity to hold more than " + contentsOfBag.length + " strings:");testAdd(aBag, contentsOfBag);// Tests on a bag that is not emptytestIsEmpty(aBag, false);String[] testStrings2 = {"A", "B", "C", "D", "A"};testFrequency(aBag, testStrings2);testContains(aBag, testStrings2);// Removing stringsString[] testStrings3 = {"", "B", "A", "C", "Z"};testRemove(aBag, testStrings3);System.out.println("\nClearing the bag:");aBag.clear();testIsEmpty(aBag, true);displayBag(aBag);}// Tests the method add.public static void testAdd(BagInterface<String> aBag, String[] content) {System.out.println("Adding ");for(int index = 0; index < content.length; index++) {aBag.add(content[index]);System.out.print(content[index] + " ");} // end for
        System.out.println();displayBag(aBag);} // end testAddprivate static void testRemove(BagInterface<String> aBag, String[] tests) {for (int index = 0; index < tests.length; index++) {String aString = tests[index];if (aString.equals("") || (aString == null)) {// test remove()System.out.println("\nRemoving a string from the bag:");String removedString = aBag.remove();System.out.println("remove() returns " + removedString);}else {// test remove(aString)System.out.println("\nRemoving \"" + aString + "\" from the bag:");boolean result = aBag.remove(aString);System.out.println("remove(\"" + aString + "\") returns " + result);} // end if
            displayBag(aBag);} // end for
        } // end testRemove// Tests the method toArray while displaying the bag.private static void displayBag(BagInterface<String> aBag) {System.out.println("The bag contains " + aBag.getCurrentSize() +" string(s), as follows:");Object[] bagArray = aBag.toArray();for (int index = 0; index < bagArray.length; index++) {System.out.print(bagArray[index] + " ");} // end for
        System.out.println();} // end diaplayBag// Tests the method contains.private static void testContains(BagInterface<String> aBag, String[] tests) {System.out.println("\nTesting the method contains:");for (int index = 0; index < tests.length; index++) {String aString = tests[index];if (!aString.equals("") && (aString != null)) {System.out.println("Does this bag contain " + tests[index] +" ? " + aBag.contains(aString));} // end if} // end for} // end testContains// Tests the method getFrequencyOfprivate static void testFrequency(BagInterface<String> aBag, String[] tests) {System.out.println("\nTesting the method getFrequencyOf:");for (int index = 0; index < tests.length; index++) {String aString = tests[index];if (!aString.equals("") && (aString != null)) { System.out.println("In this bag, the count of " + tests[index] +" is " + aBag.getFrequencyOf(aString));} // end if} // end for} // end testFrequency// Tests the method isEmpty// correctResult indicates what isEmpty should return.private static void testIsEmpty(BagInterface<String> aBag, boolean correctResult) {System.out.println("Testing isEmpty with ");if(correctResult) {System.out.println("an empty bag:");}else {System.out.println("a bag that is not empty:");} // end if
        System.out.print("isEmpty finds the bag ");if(correctResult && aBag.isEmpty()) {System.out.println("empty: OK.");}else if(correctResult) {System.out.println("not empty, but it is empty: ERROR.");}else if(!correctResult && aBag.isEmpty()) {System.out.println("empty, but it is not empty: ERROR.");}else {System.out.println("not empty: OK.");} // if else
        System.out.println();} // end testIsEmpty

}

1.8 发现总结

  • 先判断核心方法,实现 ---> 测试
  • 实现其他方法 -----> 测试
  • 实现方法时,先分析输入输出,执行功能,异常处理
  • 注重代码和功能的复用性,可以再抽象出私有方法,在公共方法中判断异常等情况,私有方法可以添加前置条件
  • 私有方法只完成已指定的一个功能,不再执行第二任务
  • 已经实现的方法,即使有更好的实现,不要改动,改完后需要再次测试
  • 禁止变异警告需要写清楚禁止变异程序警告的解释
  • 防止因初始化分配空间失败而遭恶意程序调用,需要在使用bag前对初始化是否成功进行判断(借助于initialized变量 --> 抽象为方法checkInitialization)
  • 在实现接口定义的方法时,可以将接口处对方法的注释copy到实现类中
  • 对不需要保持次序的数组,remove时,可以直接将最后一项将要remove的项覆盖即可
  • toArray直接返回数组bag而不是复制数组,用户能直接访问这个私有数据,bag[index] = null,会导致数组不连续,破坏bag的完整性
  • 实现安全,考虑各种参数和情况的合法性及异常
  • 像以前的简便写法,虽然减少代码量,但是可能会造成不必要的错误,还是需要先考虑安全性
  • 编程时习惯:为public方法写doc注释,private方法写注释用//,返回时,可以定义一个变量,在最后返回变量即可,不要再代码内部返回。if, for, while, method, class, interface等,在右括号} 后写end :} // end if(空格+//+空格+end if);在if, while等开始时,{ 之前可以空一个空格;for循环遍历时,改i为index。
  • 写代码测试时,依然不随意,保持逻辑和整洁,依然有面向对象思想。

2.使用可变大小的数组实现ADT包

2.1 可变大小数组

  一般新数组要两倍于原始数组的大小。数组复制可以使用Arrays.copyOf(sourceArray, newLength)

  程序设计技巧:当增大数组时,将它的项复制到更大的数组中。应该充分地扩展数组,以减少复制代价的影响。常用的办法是倍增数组大小。

2.2 包的新实现

  方法:修改ADT包的前一个实现,通过调整数组大小使包的容量仅由计算机可用的内存量来限定。

  • 将类名改为ResizableArrayBag,这样就能区分两种实现;
  • 从数组bag的声明中删除标识符final,以便可用调整它的大小;
  • 修改构造方法的名字以匹配新的类名;
  • 修改方法add的定义,让它总能容纳新项。该方法永远不会返回假,因为包永远不会满。

  方法add:

public boolean add(T newEntry) {checkInitialization();if(isArrayFull()) {doubleCapacity();} // end if// Assertion : result is true herebag[numberOfEntries++] = newEntry;return true;
} // end add

// Doubles the size of the array bag.

private void doubleCapacity() {

}

  增加容量需要检查是否超出最大容量MAX_CAPACITY.构造方法中也需要同样检查,定义私有方法checkCapacity。

// Doubles the size of the array bag.private void doubleCapacity() {int newLength = 2 * bag.length;checkCapacity(newLength);bag = Arrays.copyOf(bag, newLength);} // end doubleCapacityprivate void checkCapacity(int capacity) {if (capacity > MAX_CAPACITY) {throw new IllegalStateException("Attempt to create a bag whose "+ "capacity exeeds allowed maximun of " + MAX_CAPACITY);} // end if} // end checkCapacity

  构造方法:

public ResizableArrayBag(int capacity) {checkCapacity(capacity);// The cast is safe because the new array contains null entries.@SuppressWarnings("unchecked")T[] tempBag = (T[])new Object[capacity]; // Unchecked entries.bag = tempBag;numberOfEntries = 0;initialized = true;                      // Last action    } // end constructor

  增加构造方法:

/*** Creates a bag containing given entries.* @param contents: An array of objects.*/public ResizableArrayBag(T[] contents) {checkCapacity(contents.length);bag = Arrays.copyOf(contents, contents.length);numberOfEntries = contents.length;initialized = true;} // end constructor

  设计决策:

    方法add布尔方法而不是void:要和接口定义保持一致

    定义私有方法,只被add使用一次:一个方法只执行一个动作的哲学理念。

  程序设计技巧:实现了声明ADT操作的单一接口的类,应该将定义在接口中的方法声明为公有方法。但是,类还可以定义私有方法和保护方法。

  测试类:(把测试当做写代码的一部分,得学得改!!!

/** A demonstration of the class ResizableArrayBag@author Frank M. Carrano@version 4.0
*/
public class ResizableArrayBagDemo
{public static void main(String[] args) {// A bag whose initial capacity is smallBagInterface<String> aBag = new ResizableArrayBag<String>(3);testIsEmpty(aBag, true);System.out.println("Adding to the bag more strings than its initial capacity.");String[] contentsOfBag = {"A", "D", "B", "A", "C", "A", "D"};testAdd(aBag, contentsOfBag);testIsEmpty(aBag, false);String[] testStrings2 = {"A", "B", "C", "D", "Z"};testFrequency(aBag, testStrings2);testContains(aBag, testStrings2);// Removing stringsString[] testStrings3 = {"", "B", "A", "C", "Z"};testRemove(aBag, testStrings3);System.out.println("\nClearing the bag:");aBag.clear();testIsEmpty(aBag, true);displayBag(aBag);} // end main// Tests the method add.private static void testAdd(BagInterface<String> aBag, String[] content){System.out.print("Adding to the bag: ");for (int index = 0; index < content.length; index++){aBag.add(content[index]);System.out.print(content[index] + " ");} // end for
      System.out.println();displayBag(aBag);} // end testAdd// Tests the two remove methods.private static void testRemove(BagInterface<String> aBag, String[] tests){for (int index = 0; index < tests.length; index++){String aString = tests[index];if (aString.equals("") || (aString == null)){// test remove()System.out.println("\nRemoving a string from the bag:");String removedString = aBag.remove();System.out.println("remove() returns " + removedString);}else{// test remove(aString)System.out.println("\nRemoving \"" + aString + "\" from the bag:");boolean result = aBag.remove(aString);System.out.println("remove(\"" + aString + "\") returns " + result);} // end if
         displayBag(aBag);} // end for} // end testRemove// Tests the method isEmpty.// correctResult indicates what isEmpty should return.   private static void testIsEmpty(BagInterface<String> aBag, boolean correctResult){System.out.print("Testing isEmpty with ");if (correctResult)System.out.println("an empty bag:");elseSystem.out.println("a bag that is not empty:");System.out.print("isEmpty finds the bag ");if (correctResult && aBag.isEmpty())System.out.println("empty: OK.");else if (correctResult)System.out.println("not empty, but it is empty: ERROR.");else if (!correctResult && aBag.isEmpty())System.out.println("empty, but it is not empty: ERROR.");elseSystem.out.println("not empty: OK.");      System.out.println();} // end testIsEmpty// Tests the method getFrequencyOf.private static void testFrequency(BagInterface<String> aBag, String[] tests){System.out.println("\nTesting the method getFrequencyOf:");for (int index = 0; index < tests.length; index++)System.out.println("In this bag, the count of " + tests[index] + " is " + aBag.getFrequencyOf(tests[index]));} // end testFrequency// Tests the method contains.private static void testContains(BagInterface<String> aBag, String[] tests){System.out.println("\nTesting the method contains:");for (int index = 0; index < tests.length; index++)System.out.println("Does this bag contain " + tests[index] + "? " + aBag.contains(tests[index]));} // end testContains// Tests the method toArray while displaying the bag.private static void displayBag(BagInterface<String> aBag){System.out.println("The bag contains " + aBag.getCurrentSize() +" string(s), as follows:");        Object[] bagArray = aBag.toArray();for (int index = 0; index < bagArray.length; index++){System.out.print(bagArray[index] + " ");} // end for
        System.out.println();} // end displayBag
} // end ResizableArrayBagDemo/*Testing isEmpty with an empty bag:isEmpty finds the bag empty: OK.Adding to the bag more strings than its initial capacity.Adding to the bag: A D B A C A DThe bag contains 7 string(s), as follows:A D B A C A DTesting isEmpty with a bag that is not empty:isEmpty finds the bag not empty: OK.Testing the method getFrequencyOf:In this bag, the count of A is 3In this bag, the count of B is 1In this bag, the count of C is 1In this bag, the count of D is 2In this bag, the count of Z is 0Testing the method contains:Does this bag contain A? trueDoes this bag contain B? trueDoes this bag contain C? trueDoes this bag contain D? trueDoes this bag contain Z? falseRemoving a string from the bag:remove() returns DThe bag contains 6 string(s), as follows:A D B A C ARemoving "B" from the bag:remove("B") returns trueThe bag contains 5 string(s), as follows:A D A A CRemoving "A" from the bag:remove("A") returns trueThe bag contains 4 string(s), as follows:C D A ARemoving "C" from the bag:remove("C") returns trueThe bag contains 3 string(s), as follows:A D ARemoving "Z" from the bag:remove("Z") returns falseThe bag contains 3 string(s), as follows:A D AClearing the bag:Testing isEmpty with an empty bag:isEmpty finds the bag empty: OK.The bag contains 0 string(s), as follows:
*/

2.3 使用数组实现ADT包的优缺点

  数组易于使用,知道下标就能立即访问。

使用数组来实现ADT包时:

  • 向包中添加项是快的;
  • 删除未指定的项是快的;
  • 删除某个项需要找到这个项的时间;
  • 增大数组的大小需要复制项的时间。

转载于:https://www.cnblogs.com/datamining-bio/p/9617586.html

(二)使用数组长度实现ADT bag(java)相关推荐

  1. java获取二维数组长度

    java获取二维数组长度 二维数组定义:int array[][] = new int[3][4]; 获取行数: int rowLength = array.length;//3 获取列数: int ...

  2. 某年级三个班的Java考试成绩如下表所示,请采用二维数组保存这些数据(Java实验)

    某年级三个班的Java考试成绩如下表所示,请采用二维数组保存这些数据 1班 99 68 97     2班 89 95 88 59 64 3班 89 79 99 58   4班 59 79 85 63 ...

  3. python 二维数组长度_剑指offer二维数组中的查找【Java+Python】

    点击上方"蓝字",关注了解更多 二维数组中的查找 1. 题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序 ...

  4. java二维数组长度表示,java二维数组指定不同长度代码实例

    本篇文章小编给大家分享一下java二维数组指定不同长度代码实例,文章代码介绍的很详细,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看. 1.二维数组的每个元素都是一个一维数组, ...

  5. 关于java二维数组长度(length)的知识

    二话不说,呈上代码 //定义一个整型数组:3行4列 int a[][] = new int[3][4]; //获取行数---3行 int lenY = a.length; //获取列数---4列 in ...

  6. 《剑指Offer》面试题四(牛客网在线编程第一题):二维数组中的查找(Java实现)

    题目:在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. ...

  7. php获取一维,二维数组长度的方法(有实例)

    在php中获取数组长度方法很简单,php为我们提供了两个函数可以计算一维数组长度,如count,sizeof都可以直接统计数组长度哦,下面我们来看几个实例吧. php如何获取数组的长度,使用php函数 ...

  8. 剑指Offer #01 二维数组中的查找(Java描述)

    题目来源:牛客网-剑指Offer专题 题目地址:二维数组中的查找 题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一 ...

  9. python 二维数组 长度_Python创建二维数组的正确姿势

    ↑↑↑点击上方"蓝字",关注"极客猴" 如果你喜欢极客猴,可以把我置顶或加为星标 题图:by watercolor.illustrations from Ins ...

最新文章

  1. Linux系统内存的Cached Memory
  2. mysql proxy 悲观锁_使用MySQL悲观锁解决电商扣库存并发问题
  3. 阿里巴巴数据分析沙龙 杭州站圆满召开
  4. Python之ORM
  5. 管理员获得所有权_在Windows 7中获得注册表项的所有权
  6. Python环境搭建与连接SQL Server类MyDBase的实现
  7. Win7虚拟无线AP以及Android手机抓包
  8. 在Ubuntu 18.04系统上安装和配置DBeaver的步骤
  9. MySql-流程函数
  10. ps cc 生成html,使用photoshop生成网页的方法
  11. linux的前端环境搭建-安装配置git客户端与github连接
  12. 关于random的多种用法
  13. HINSTANCE HANDLE HWND 的区别及一般方法
  14. 利用函数imnoise2处理噪声污染和spfilt处理滤波器
  15. matlab仿真模糊PID控制,基于Matlab的模糊PID控制器的设计和仿真
  16. 用Django2.1开发易班联合登录
  17. 计算机网络 自顶向下方法 (一) 笔记 总结 第一章 概述
  18. 数据库--T-SQL创建数据库表
  19. GMS2(Gamemaker Studio 2)运行工程时遇到的问题解决
  20. 基础技术篇 10 ——物联网常见通信协议与通讯协议梳理【下】- 通信协议

热门文章

  1. 【Flask】官方教程(Tutorial)-part2:蓝图-视图、模板、静态文件
  2. 字符串转换成十进制整数
  3. 如果你有一个机器人女友
  4. 关于textarea中的回车符
  5. suma++[代碼分析一]: 主入口visualizer.cpp
  6. 什么是SAAS——软件即服务
  7. 《游戏设计模式》学习笔记
  8. 11.9 leetcode打卡
  9. 四位大小写字母和数字随机验证码
  10. 图表嵌入到数据表格下方_Excel中进行图表下方显示数据表的操作技巧