`
Tony_Lee-S
  • 浏览: 82799 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

线性表(用数组存储数据)

阅读更多

线性表是按顺序存储数据时常用的一种数据结构。例如,学生的列表、空房间的列表、城市的列表以及书籍的列表。使用数组存储线性表的元素是实现线性表的其中一种方式。

下面以袋集合为例,介绍数组线性表。袋可以定义为一种没有按照任何特定位置关系来组织其元素的组合。从概念上讲,它类似于放置物品的真实袋子。一旦将元素放入袋中,将不能确定袋中元素的相对位置。如果进入袋中盲目地取出一个元素,则元素的取出几率是相同的。袋是一种非线性集合。这种集合中的元素实质上根本就没有任何组织方式。袋中的元素相互间没有任何固有关系,而且元素也没有按照特定的次序添加到袋中。

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语言课程设计线性表&数组学生成绩管理系统"是一个实践性的学习任务,旨在帮助学生深入理解和应用C语言编程知识,特别是关于线性表和数组的数据结构。下面将详细阐述相关知识点。 1. **C语言基础**: ...

    数据结构 线性表实验代码 C语言 数组

    在这个实验代码中,我们关注的是使用C语言实现线性表,并采用数组作为底层存储机制。 线性表的基本操作包括: 1. 初始化:创建一个空的线性表,通常用一个空数组来表示。 2. 插入元素:在线性表的特定位置插入一个...

    cpp代码-线性表的数组存储,实现了快速排序,用vector存储数据

    在本项目中,我们主要探讨的是使用C++编程语言实现线性表的数组存储以及快速排序算法。线性表是一种基本的数据结构,它由n(n&gt;=0)个相同类型元素构成的有限序列,而数组存储是线性表的一种常见方式,能够提供连续的...

    数据结构 线性表 实验代码 C++ 数组

    线性表的数组实现,也被称为顺序表,是将线性表的所有元素存储在一个固定大小的一维数组中。这种实现方式的优点在于访问元素速度快,因为数组的元素可以通过索引直接访问,时间复杂度为O(1)。然而,插入和删除元素时...

    C++ 数据结构线性表-数组实现

    总的来说,C++中的线性表数组实现涉及到了动态内存分配、对象生命周期管理、数组操作以及基本数据结构的操作方法实现。这样的实现允许高效地访问和修改数组内的元素,但由于数组大小固定,插入和删除操作在表满或...

    关于线性表的顺序存储和链式存储结构的实验报告

    线性表的顺序存储结构使用数组来实现,数组中的元素可以是基本数据类型,也可以是指针等复合数据类型。在这个实验报告中,顺序存储结构通过定义一个结构体来表示线性表,包括三个字段:elem表示线性表首元素的地址,...

    线性表的顺序存储 线性表的顺序存储

    在顺序存储结构中,线性表的元素被存储在一个一维数组中,按照它们在表中的相对位置来表示数据之间的逻辑关系。这种方式简单直观,易于理解和操作。 线性表的顺序存储具有以下特点: 1. **连续存储**:所有元素存储...

    用数组实现线性表各种操作(C语言)完结

    这篇博客“用数组实现线性表各种操作(C语言)完结”很可能是详细介绍了如何使用C语言中的数组来构建并操作线性表。 线性表的操作主要包括: 1. 初始化:创建一个空的线性表,通常是在数组中分配空间,并将其长度设...

    数组,线性表的推广,很有趣哦

    数组知识点总结 一、数组的概念 数组是一种数据结构,其特点是结构中的元素本身可以是具有某种结构的...数组是一种重要的数据结构,数组的概念、定义、存储结构、操作、应用和与线性表的区别都是数组的重要知识点。

    数据结构 线性表 栈 串 数组 树 图 排序 查找

    线性表、栈、串、数组和树是数据结构中的基本类型,它们各自有着独特的特点和应用场景。 1. **线性表**:线性表是最基础的数据结构之一,它是由n个相同类型元素构成的有限序列。线性表可以顺序存储,如数组,也可以...

    数组、链表、堆栈和队列、线性表和顺序表 数组和链表.pdf

    数组是使用一块连续的内存空间保存数据,保存的数据的个数在分配内存的时候就是确定的。访问数组中第n个数据的时间花费是O(1),但是要在数组中查找一个指定的数据则是O(N)。当向数组中插入或者删除数据的时候,最好...

    数组实现线性表 数据结构

    本文主要介绍如何使用数组来实现线性表这一基本数据结构。 #### 线性表定义与特点 线性表是一种线性数据结构,它是由一组相同类型的数据元素构成的有限序列。这些数据元素之间存在一种一对一的关系,即每个元素都...

    数据结构实验报告1线性表的顺序存储结构.doc

    顺序存储结构是指线性表的元素在内存中是连续存放的,通常使用数组来实现。在实验中,线性表的数据类型为`ElemType`,这里假设为整型`int`,并使用一个结构体`List`来封装线性表的相关信息,包括元素指针`list`、...

    1. 线性表-顺序存储-数组1

    在本节中,我们主要讨论线性表的顺序存储方式,即使用数组来实现。数组是一种最简单且最基础的数据结构,它在内存中连续存储元素,每个元素可以通过一个固定的下标来访问。 时间复杂度是衡量算法效率的重要指标,它...

    线性表的顺序存储与实现

    顺序存储的线性表通常使用数组来实现。数组是一种特殊的线性数据结构,它的元素在内存中是按顺序排列的,可以通过索引来快速访问任何位置的元素。这种存储方式的优点是访问速度快,因为随机访问的时间复杂度为O(1)。...

    顺序表和数组(易混淆),线性表,链表的区别与联系 数组和链表.pdf

    链表是线性表中的一种,它的存储结构是用任意一组存储单元来存储数据元素。所以它的存储结构可以是连续的,也可以不是连续的。一般我们说的链表都是不连续的。有一种用数组来表示的链表,叫做静态链表,它的存储结构...

    数据结构-线性表的顺序存储

    顺序存储是线性表的一种常见存储方式,尤其在计算机内存中,顺序存储结构通常指的是数组。下面将详细讨论线性表的顺序存储及其相关知识点。 1. **数组**:顺序存储的基础是数组,数组是一种连续的内存空间,每个...

    数据结构复习(1)---线性表的顺序存储结构及实现

    - 数组:在C/C++中,通常使用数组来实现顺序存储的线性表。数组的下标对应线性表中的位置,可以直接通过下标访问元素。 - 动态数组:为了解决数组长度固定的问题,可以使用动态数组,如Java中的ArrayList。动态...

Global site tag (gtag.js) - Google Analytics