线性表是按顺序存储数据时常用的一种数据结构。例如,学生的列表、空房间的列表、城市的列表以及书籍的列表。使用数组存储线性表的元素是实现线性表的其中一种方式。
下面以袋集合为例,介绍数组线性表。袋可以定义为一种没有按照任何特定位置关系来组织其元素的组合。从概念上讲,它类似于放置物品的真实袋子。一旦将元素放入袋中,将不能确定袋中元素的相对位置。如果进入袋中盲目地取出一个元素,则元素的取出几率是相同的。袋是一种非线性集合。这种集合中的元素实质上根本就没有任何组织方式。袋中的元素相互间没有任何固有关系,而且元素也没有按照特定的次序添加到袋中。
UML描述
接口实现
import java.util.Itrator;
public interface BagADT
{
// Adds one element to this bag
public void add (Object element);
// Removes and returns a random element from this bag
public Object removeRandom ();
// Removes and retruns the specified element from this bag
public Object remove (Object element);
// Returns the union of this bag and the parameter
public BagADT union (BagADT set);
// Returns true if this bag contains the parameter
public boolean contains (Object target);
// Returns true if this bag and the parametr contain exactly the
// same elements
public boolean equals (BAgADT bag);
// Returns true if this set contains no elements
public boolean isEmpty ();
// Returns the number of elements in this set
public int size ();
// Returns an iterator for the elements in this bag
public Iterator iterator ();
// Returns a string representation of this bag
public String toString ();
}
注意某些方法的返回类型是BagADT,这表示它们返回一个袋集合。但是通过使用接口名作为返回类型,接口就没有将方法的调用委托给任何实现袋的类。对于接口的定义来说,这非常重要,因为接口并没有人为地绑定到某个特定的实现。接收袋集合作为参数的方法也是同样的道理。
ArrayBag类
ArrayBag类实现BagDAT接口,因而必须定义该接口中列出的方法。记住,实现某个接口的类还要定义其他的方法。
ArrayBag类的关键实例数据包括:一个数组(contents),用于存储袋中的对象;整形变量count,用于记录集合中元素的个数。还要定义一个Random对象,以支持袋中随机元素的绘制;一个定义默认容量的常量(DEFAULT_CAPACITY);一个名为NOT_FOUND的常量,以有助于操作查找特定的元素。ArrayBag类的实例数据声明如下:
private static Random rand = new Random();
private final int DEFAULT_CAPACITY = 100;
private final int NOT_FOUND = -1;
private int count;
private Object [] contents;
注意,Random对象声明为一个静态变量,在其声明中(而不是在构造函数中)进行实例化。因为Random对象是静态变量,所以ArrayBag类的所有实例均共享该变量。这种做法将避免因创建两个袋,但它们的随机数产生器却使用相同的种子值(seed value)而带来的问题。
变量count的值实际上表示两个相关的信息。首先,它表示当前存储在袋集合中的元素个数;其次,因为Java数组的索引从0开始,所以它还表示数组中下一个可以存储新元素的空位置。一方面,变量count的值表示集合的抽象状态,另一方面它又有助于我们了解集合的内在实现。
下面定义了ArrayBag类的构造函数,它创建一个初始为空的袋。变量count的值设置为0,并且实例化用于存储袋中元素的数组。该构造函数将contents数组 的初始容量设置为一个默认值。
// Create an empty bag using the default capacity
public ArrayBag()
{
count = 0;
contents = new Object [DEFAULT_CAPACITY];
}
因为在特定的情况下,用户可能知道袋中将要存储元素的大致数目,因而在开始时可以指定该值。所以我们还可以提供另一个有参构造函数,它接收一个表示contents数组的初始容量的整形参数。这个有参构造函数定义如下:
// Creat an emptybag using the specified capacity
public ArrayBag (int initialCapacity)
{
count = 0;
contents = new Object [initialCapacity];
}
方法
size和isEmpty方法
size方法仅仅返回count变量的值:
// Returns the number of elements currently in this bag
public int size()
{
retrurn count;
}
isEmpty方法在count变量的值为0时返回真:
// Returns true if this bag is empty and false otherwise
public boolean isEmpty()
{
return (count == 0);
}
ArrayBag实现在多种情况中需要依赖count的值。它是集合表示的基础。因此,所有改变袋集合状态的操作都必须仔细地维护count值的一致性。
add方法
该方法 的目的是将其接收的Object参数添加到袋集合中。如果数据结构的容量是固定的,则add方法必须考虑数组填满的情况。其解决方案是在这种情况发生时自动地扩展数组的容量。
// Adds the specified element to the bag, expanding the capacity of the bag array if necessary.
public void add (Object element)
{
if (size() == contents.length)
expandCapacity();
contents[count] = element;
count ++;
}
expandCapacity方法创建一个新的数组,其容量是当前存储袋中元素的数组的2倍,并将当前数组中的所有引用复制到这个新数组中,然后将重新设置实例变量contents,使其指向larger数组。
// wtice the capacity of the old one.
private void expandCapacity()
{
Object [] larger = new Object [contents.length*2];
for (int index = 0; index < contents.length; index++)
larger [index] = contents [index];
contents = larger;
}
注意,expandCapacity方法的可见性声明为private。它设计为一个支持方法(support method),而不是作为提供给袋集合用户的方法。
addAll方法
addAll方法的目的是将一个袋中的所有对象添加到袋集合中。对于我们的数组实现,这意味着可以使用iterator方法遍历一个袋中的所有元素,然后使用add方法将它们添加到当前的袋中。以这种方式使用add方法的一个优点是,该方法将检查容量,并在必要时扩展数组。
// Adds the contents of the parameter to this bag.
public void addAll (BagADT bag)
{
Iterator scan = bag.iterator();
while (scan.hasNext())
add (scan.next());
}
removeRandom方法
removeRandom方法从集合中随机地选择一个元素,并从集合中删除该元素,然后将其返回给调用方法。如果袋集合为空,则该方法将抛出EmptyBagException异常。
// Removes a random elelment from the bag and returns it .Throws an EmptyBagException if the bag is empty.
public Object removeRandom () throws EmptyBagException
{
if (isEmpty())
throw new EmptyBagException();
int choice = rand.nextInt(count);
Object result = contents [choice];
contents [choice] = contents [count - 1];
contents [count - 1] = null;
count --;
}
袋集合的这种实现方法将袋中的所有元素从一端开始连续地存储在contents数组中。因为该方法删除某个元素,所以必须以某种方式填补空缺。可以使用一个循环将所有的元素向低位移动一个位置,但是这样做是不必要的。因为数组中不存在次序,所以可以简单地将最后一个数组元素放置在存储删除元素的单元中,这样就不需要循环了。
remove方法
remove方法从袋中删除指定的元素,并返回该元素。但袋允许出现重复的元素。这意味着如果袋中存在相同的两个元素,则删除其中一个,而保留另一个。如果为空袋,则该方法将抛出EmptyBagException异常,如果袋中并不存在目标元素,则抛出NoSuchElementException异常。
// Removes one occurance of the specificed element from the bag and rerurn it. Throws an EmptyBagExceptionif the bag is empty and a NosuchElementException if the taget is not in the bag.
public Object remove (Object target) throws EmptyBagException,NoSuchElementException
{
int search = NOT_FOUND;
if (isEmpty())
throw new EmptyBagException();
for (int index = 0; index < count && search == NOT_FOUND; index ++)
if (contents [index].equals (target))
search = index;
if (search == NOT_FOUND)
throw new NoSuchElementException();
Object result = contents[search];
contents[search] = contents[count - 1];
contents[count - 1] = null;
count --;
return result;
}
union方法
union方法返回一个新袋,新袋包含原来两个袋中的所有元素。使用构造函数创建一个新袋,然后遍历数组,并使用add方法将当前袋中的元素添加到这个新袋中。接下来,我们为任务参数的袋创建一个迭代器,然后该袋中的每个元素,并将它们添加到新袋中。因为袋中的元素没有固有的次序,所以首先添加哪个袋中的内容无关紧要。
// Returns a new bag that is the union of this bag and the parameter.
public BagADT union (BagADT bag)
{
ArrayBag both = new ArrayBag();
for (int index = 0; index < count; index++)
both.add (contents [index]);
Iterator scan = bag.iterator();
while (scan = bag.hasNext())
both.add(scan.next());
return both;
}
contains方法
在袋包含指定的目标元素时,contains方法返回真。
// Returns true if this bag contains the specified target element.
public boolean contains (Objct target)
{
int search = NOT_FOUND;
for(int index = 0; index < count && search == NOT_FOUND; index ++)
if(contents[index].equals(target))
search = index;
return (search != NOT_FOUND);
}
equals方法
在当前的袋所包含的元素确实与传递为参数的袋的元素相同时,equals方法返回真。
// Returns true if this bag contains exactly the same elements as the parameter.
public boolean equals (BagADT bag)
{
boolean result = false;
ArrayBag temp1 = new ArrayBag();
ArrayBag temp2 = new ArrayBag();
Object obj;
if(size() == bag.size())
{
temp1.addAll(this);
temp2.addAll(bag);
Iterator scan = bag.iterator();
while(scan.hasNext())
{
obj = scan.next();
if(temp2.contains(obj))
{
temp1.remove(obj);
temp2.remove(obj);
}
}
result = (temp1.isEmpty() && temp2.isEmpty());
}
return result;
}
toString方法
toString方法将袋中每个球的字母和数字构成一个字符串,然后返回它。
// Returns a string representation of thisbag.
public String toString()
{
String result = "";
for (int index = 0; index < count; index ++)
result = result + contents[index].toString() + "\n";
return result;
}
iterator方法
iterator方法通过ArrayIterator类实现。
// Returns an iterator for the elements currently in this bag
public Iterator iterator()
{
rerurn new ArrayIterator(contents, count);
}
ArryIterator类:
import java.util.*;
public class ArrayIterator implements Iterator
{
private int count;
private int current;
private Object[] items;
// Set up this iterator using the specified items.
public ArrayIter(Object[] collection, int size)
{
items = collection;
count = size;
current = 0;
}
// Returns true if this iterator has at least one more element to deliver in the iteraion.
public boolean hasNext()
{
return (current < count);
}
// Returns the next element in the iteration. If therer are no more elements in this itertion,a NoSuchElementException is thrown.
public Object next()
{
if(! hasNext())
throw new NoSuchElementException();
current ++;
return items[current - 1];
}
分享到:
相关推荐
在本项目中,"C语言课程设计线性表&数组学生成绩管理系统"是一个实践性的学习任务,旨在帮助学生深入理解和应用C语言编程知识,特别是关于线性表和数组的数据结构。下面将详细阐述相关知识点。 1. **C语言基础**: ...
在这个实验代码中,我们关注的是使用C语言实现线性表,并采用数组作为底层存储机制。 线性表的基本操作包括: 1. 初始化:创建一个空的线性表,通常用一个空数组来表示。 2. 插入元素:在线性表的特定位置插入一个...
在本项目中,我们主要探讨的是使用C++编程语言实现线性表的数组存储以及快速排序算法。线性表是一种基本的数据结构,它由n(n>=0)个相同类型元素构成的有限序列,而数组存储是线性表的一种常见方式,能够提供连续的...
线性表的数组实现,也被称为顺序表,是将线性表的所有元素存储在一个固定大小的一维数组中。这种实现方式的优点在于访问元素速度快,因为数组的元素可以通过索引直接访问,时间复杂度为O(1)。然而,插入和删除元素时...
总的来说,C++中的线性表数组实现涉及到了动态内存分配、对象生命周期管理、数组操作以及基本数据结构的操作方法实现。这样的实现允许高效地访问和修改数组内的元素,但由于数组大小固定,插入和删除操作在表满或...
线性表的顺序存储结构使用数组来实现,数组中的元素可以是基本数据类型,也可以是指针等复合数据类型。在这个实验报告中,顺序存储结构通过定义一个结构体来表示线性表,包括三个字段:elem表示线性表首元素的地址,...
在顺序存储结构中,线性表的元素被存储在一个一维数组中,按照它们在表中的相对位置来表示数据之间的逻辑关系。这种方式简单直观,易于理解和操作。 线性表的顺序存储具有以下特点: 1. **连续存储**:所有元素存储...
这篇博客“用数组实现线性表各种操作(C语言)完结”很可能是详细介绍了如何使用C语言中的数组来构建并操作线性表。 线性表的操作主要包括: 1. 初始化:创建一个空的线性表,通常是在数组中分配空间,并将其长度设...
数组知识点总结 一、数组的概念 数组是一种数据结构,其特点是结构中的元素本身可以是具有某种结构的...数组是一种重要的数据结构,数组的概念、定义、存储结构、操作、应用和与线性表的区别都是数组的重要知识点。
线性表、栈、串、数组和树是数据结构中的基本类型,它们各自有着独特的特点和应用场景。 1. **线性表**:线性表是最基础的数据结构之一,它是由n个相同类型元素构成的有限序列。线性表可以顺序存储,如数组,也可以...
数组是使用一块连续的内存空间保存数据,保存的数据的个数在分配内存的时候就是确定的。访问数组中第n个数据的时间花费是O(1),但是要在数组中查找一个指定的数据则是O(N)。当向数组中插入或者删除数据的时候,最好...
本文主要介绍如何使用数组来实现线性表这一基本数据结构。 #### 线性表定义与特点 线性表是一种线性数据结构,它是由一组相同类型的数据元素构成的有限序列。这些数据元素之间存在一种一对一的关系,即每个元素都...
顺序存储结构是指线性表的元素在内存中是连续存放的,通常使用数组来实现。在实验中,线性表的数据类型为`ElemType`,这里假设为整型`int`,并使用一个结构体`List`来封装线性表的相关信息,包括元素指针`list`、...
在本节中,我们主要讨论线性表的顺序存储方式,即使用数组来实现。数组是一种最简单且最基础的数据结构,它在内存中连续存储元素,每个元素可以通过一个固定的下标来访问。 时间复杂度是衡量算法效率的重要指标,它...
顺序存储的线性表通常使用数组来实现。数组是一种特殊的线性数据结构,它的元素在内存中是按顺序排列的,可以通过索引来快速访问任何位置的元素。这种存储方式的优点是访问速度快,因为随机访问的时间复杂度为O(1)。...
链表是线性表中的一种,它的存储结构是用任意一组存储单元来存储数据元素。所以它的存储结构可以是连续的,也可以不是连续的。一般我们说的链表都是不连续的。有一种用数组来表示的链表,叫做静态链表,它的存储结构...
顺序存储是线性表的一种常见存储方式,尤其在计算机内存中,顺序存储结构通常指的是数组。下面将详细讨论线性表的顺序存储及其相关知识点。 1. **数组**:顺序存储的基础是数组,数组是一种连续的内存空间,每个...
- 数组:在C/C++中,通常使用数组来实现顺序存储的线性表。数组的下标对应线性表中的位置,可以直接通过下标访问元素。 - 动态数组:为了解决数组长度固定的问题,可以使用动态数组,如Java中的ArrayList。动态...