目标:

1) 描述数据的链式组织方式

2) 描述如何在链式节点链的开头添加新节点

3) 描述如何删除链式节点链的首节点

4) 描述如何在链式节点链中找到某个数据

5) 使用链式节点链实现ADT包

6) 描述基于数组实现和链式实现的ADT包的不同

3. 使用链式数据实现包

3.1链式数据

  添加到开头形成一个链

3.2 ADT包的链式实现

  3.2.1 私有类Node

  节点(node),data域:数据部分(data portion),next域:链接部分(link portion)

  Node是ADT包的实现细节,应该对包的客户隐藏。一种方法是定义在包中,且含在实现包的类中。

private class Node{
private T data; // Entry in bag
private Node next; // Link to next node private Node(T dataPortion) {
this(dataPortion, null);
} // end constructor private Node(T dataPortion, Node nextNode) {
data = dataPortion;
next = nextNode;
} // end constructor
} // end Node

3.2.2 类LinkedBag的框架

  头引用(head reference)的数据域来保存指向第一个节点的引用,第二个数据域可以记录包中项的个数,即链中节点的个数。

/**
* A class of bags whose entries are stored in a chain of linked nodes.
* The bag is never full
* @author Administrator
*
* @param <T>
*/
public class LinkedBag<T> implements BagInterface<T> {
  private Node firstNode; // Reference to first node
  private int numberOfEntries;   public LinkedBag() {
    firstNode = null;
    numberOfEntries = 0;
  } // end default constructor   @Override
  public int getCurrentSize() {
    // TODO Auto-generated method stub
    return 0;
  }   @Override
  public boolean isEmpty() {
    // TODO Auto-generated method stub
    return false;
  }   @Override
  public boolean add(Object newEntry) {
    // TODO Auto-generated method stub
    return false;
  }   @Override
  public Object remove() {
    // TODO Auto-generated method stub
    return null;
  }   @Override
  public boolean remove(Object anEntry) {
    // TODO Auto-generated method stub
    return false;
  }   @Override
  public void clear() {
    // TODO Auto-generated method stub
  }   @Override
  public int getFrequencyOf(Object anEntry) {
    // TODO Auto-generated method stub
    return 0;
  }   @Override
  public boolean contains(Object anEntry) {
    // TODO Auto-generated method stub
    return false;
  }   @Override
  public Object[] toArray() {
    // TODO Auto-generated method stub
    return null;
  }   private class Node{
    private T data; // Entry in bag
    private Node next; // Link to next node
    private Node(T dataPortion) {
      this(dataPortion, null);
    } // end constructor     private Node(T dataPortion, Node nextNode) {
      data = dataPortion;
      next = nextNode;
    } // end constructor
  } // end Node
}

  注意:没有定义initialized变量表示初始化状态。

3.2.3 定义一些核心方法

  方法add:

/**
* 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) { // OutOfMemoryError posiible
Node newNode = new Node(newEntry);
newNode.next = firstNode; // Make new node reference test of chain
// (firstNode is null if chain is empty)
firstNode = newNode; // New node is at beginning of chain
numberOfEntries++;
return true;
} // end add

  安全说明:内层类Node应该执行安全检查吗?

  因为Node是私有内层类,所以将它看做外层类LinkedBag的实现细节。因此,让LinkedBag负责所有的安全检查。另外,注意Node的构造方法只做了简单的赋值,并没有抛出异常,即使不是这种情况,Node抛出了异常,LinkedBag也应该能处理它。

  安全说明:类LinkedBag应该执行安全检查吗?

  默认构造方法只进行了两个简单的赋值。实际上,所赋的值与省略构造方法时使用默认的赋值是一样的值。这些赋值不会失败。add分配新的节点,如果没有足够的内存空间,这个分配可能会失败,OutOfMemoryError,链完好无损且保持不变。或者是空的或者含有之前的节点。若客户捕获这个异常并处理,这样操作属于恰当。因为任何LinkedBag对象的完整性已经得到维护,所以不需要为类ArrayBag添加的那些安全检查。

  方法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 cast
int index = 0;
Node currentNode = firstNode;
while((index < numberOfEntries) && (currentNode != null)) {
result[index] = currentNode.data;
index++;
currentNode = currentNode.next;
} // end while
return result;
} // end toArray

3.2.4 测试核心方法

/**
* A test of the methods add, toArray, isEmpty, and getCurrentSize,
* as defined in the first draft of the class LinkedBag
* @author Administrator
*
*/
public class LinkedBagDemo1 { public static void main(String[] args) {
System.out.println("Creating an empty bag:");
BagInterface<String> aBag = new LinkedBag<>();
testIsEmpty(aBag, true);
displayBag(aBag); String[] contentOfBag = {"A", "D", "B", "A", "C", "A", "D"};
testAdd(aBag, contentOfBag);
testIsEmpty(aBag, false);
} public static void testAdd(BagInterface<String> bag, String[] content) {
System.out.println("Testing the add method:");
for (int index = 0; index < content.length; index++) {
if(bag.add(content[index])) {
System.out.print(content[index] + " ");
} // end if
} // end for
System.out.println();
displayBag(bag);
} // end testAdd private static void displayBag(BagInterface<String> bag) {
System.out.println("the bag contains " + bag.getCurrentSize() +
" string(s), as follows:");
Object[] bagArray = bag.toArray();
for (int index = 0; index < bagArray.length; index++) {
System.out.print(bagArray[index] + " ");
} // end for
System.out.println();
} // end displayBag 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
}

  3.2.5 方法getFrequencyOf

/**
* 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) {
Node currentNode = firstNode;
int counter = 0;
int loopCounter = 0;
while((loopCounter < numberOfEntries) && (currentNode != null)) {
if(currentNode.data.equals(anEntry)) {
counter++;
} // end if
loopCounter++;
currentNode = currentNode.next;
} // end while
return counter;
} // end getFrequencyOf

  3.2.6 方法contains

/**
* 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) {
Node currentNode = firstNode;
boolean found = false;
while(!found && (currentNode != null)) {
if(currentNode.data.equals(anEntry)) {
found = true;
break;
}
else {
currentNode = currentNode.next;
} // end if
} // end while
return false;
} // end contains

3.3 从链中删除一项

  删除未指定项:remove()

/**
* 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() {
T result = null;
if(firstNode != null) {
result = firstNode.data;
firstNode = firstNode.next;
numberOfEntries--;
} // end if
return result;
} // end remove

  删除指定项:remove(T)

  删除思想与Array相同,用首节点的值将其替换,然后firstNode=firstNode.next。

/**
* 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) {
boolean result = false;
Node nodeN = getReferenceTo(anEntry);
if(nodeN != null) {
nodeN.data = firstNode.data;
firstNode = firstNode.next;
numberOfEntries--;
result = true;
} // end if
return result;
} // end remove // Locates a given entry within this bag.
// Returns a reference to the node containing the entry, if located,
// or null otherwise.
private Node getReferenceTo(T anEntry) {
Node currentNode = firstNode;
while(currentNode != null) {
if(currentNode.data.equals(anEntry)) {
break;
} // end if
currentNode = currentNode.next;
} // end while
return currentNode;
} // end getReferenceTo

  方法clear:

/**
* Removes all entries from this bag.
*/
@Override
public void clear() {
while(!isEmpty()) {
remove();
} // end while
} // end clear

  设计决策:LinkedBag应该限制包的容量吗?

  LinkedBag每次增加一个节点,如果添加失败,则现有的链保持不变。若希望在有限的内存状态下使用LinkedBag,仍可以限制LinkedBag的容量。

3.4 使用链实现ADT包的优缺点

  最大的优点是链可以按需求来改变大小,所以包也是如此。只要内存可用,可以在链中添加想要的任意多的节点。可以删除并回收不再需要的节点。(数组需要更大的数组且需要复制)。添加新项到数组尾货链头都简单(除过数组调大小),删除一项也都简单,指定项都需要查找。对于相同的长度,链比数组需要更大的内存。但是数组常比所需大,也有内存浪费,链按需使用。

(三)使用链式数据实现包(java)的更多相关文章

  1. 链式二叉树的实现(Java)

    定义树节点: package 链式二叉树; public class TreeNode { private Object data; private TreeNode left; private Tr ...

  2. C++ 运算符重载三(链式编程)

    //运算符重载之链式编程 #include<iostream> using namespace std; //对于友元函数重载运算符只适用于左操作数是系统变量的场景 //因为成员无法在系统 ...

  3. Python特色的序列解包、链式赋值、链式比较

    一.序列解包 序列解包(或可迭代对象解包):解包就是从序列中取出其中的元素的过程,将一个序列(或任何可迭代对象)解包,并将得到的值存储到一系列变量中. 一般情况下要解包的序列包含的元素个数必须与你在等 ...

  4. 第4.7节 Python特色的序列解包、链式赋值、链式比较

    一.序列解包 序列解包(或可迭代对象解包):解包就是从序列中取出其中的元素的过程,将一个序列(或任何可迭代对象)解包,并将得到的值存储到一系列变量中. 一般情况下要解包的序列包含的元素个数必须与你在等 ...

  5. PHP设计模式:类自动载入、PSR-0规范、链式操作、11种面向对象设计模式实现和使用、OOP的基本原则和自动加载配置

    一.类自动载入 SPL函数 (standard php librarys) 类自动载入,尽管 __autoload() 函数也能自动加载类和接口,但更建议使用 spl_autoload_registe ...

  6. 数据结构Java实现07----队列:顺序队列&顺序循环队列、链式队列、顺序优先队列

    一.队列的概念: 队列(简称作队,Queue)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作在其 ...

  7. 数据结构Java实现05----栈:顺序栈和链式堆栈

    一.堆栈的基本概念: 堆栈(也简称作栈)是一种特殊的线性表,堆栈的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置进行插入和删除操作,而堆栈只允许在固定一端进行插入和删除 ...

  8. 数据结构Java实现03----栈:顺序栈和链式堆栈

    一.堆栈的基本概念: 堆栈(也简称作栈)是一种特殊的线性表,堆栈的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置进行插入和删除操作,而堆栈只允许在固定一端进行插入和删除 ...

  9. Java实现链式存储的二叉查找树(递归方法)

    二叉查找树的定义: 二叉查找树或者是一颗空树,或者是一颗具有以下特性的非空二叉树: 1. 若左子树非空,则左子树上所有节点关键字值均小于根节点的关键字: 2. 若右子树非空,则右子树上所有节点关键字值 ...

随机推荐

  1. p1110 报表统计(FHQ-TREAP/TREAP)

    平衡树的裸题,操作都相当简单 写了一个FHQ,但是奈何常数太大,实在过不去 最后写了一个Treap开O2水过 TREAP代码 #include <cstdio> #include < ...

  2. R----ggplot2包介绍学习--转载

    https://www.cnblogs.com/nxld/p/6059603.html 分析数据要做的第一件事情,就是观察它.对于每个变量,哪些值是最常见的?值域是大是小?是否有异常观测? ggplo ...

  3. 前端分页插件bootstrapPaginator的使用

     引入bootstrap-paginator.js <table class="table table-striped table-bordered table-hover dataT ...

  4. react-redux的mapStateToProps可取到state值但不会注入props

    一.问题描述 想通过react-redux和redux实现react组件之间的通信,reducer.action.store都编写正确,mapDispatchToProps也能正确传值.唯独mapSt ...

  5. 怎样更新CentOS6.5的yum源

    将yum源设置为国内yum源,可以提升软件包安装和更新的速度,同时避免一些常见软件版本无法找到. 国内源:可以使用wget获取或者直接下载 网易: CentOS5: http://mirrors.16 ...

  6. Java SE LinkedList的底层实现

    关于实现链表的底层原理 链表便于增删,不便于查询 package com.littlepage.linkedList; /** * 基于底层实现LinkedList * @author Littlep ...

  7. js_计时器之setInterval

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. [osg][osgEarth][osgGA][原] EarthManipulator------基于oe的相机漫游器(浅析)

    知识基础:osg漫游器基础 class OSGEARTHUTIL_EXPORT EarthManipulator : public osgGA::CameraManipulator EarthMani ...

  9. 谈谈JAVA实现节假日验证

    我们需要两个类,第一个类: 我们叫它验证类. 第二个类: 它是对法定节假日的抽象. 第一步开始: 当验证类被初始化的时候,会加载本年的所有法定节假日到一个list里: thisYearHolidays ...

  10. 力扣(LeetCode)476. 数字的补数

    给定一个正整数,输出它的补数.补数是对该数的二进制表示取反. 注意: 给定的整数保证在32位带符号整数的范围内. 你可以假定二进制数不包含前导零位. 示例 1: 输入: 5 输出: 2 解释: 5的二 ...