抽象数据类型
抽象数据类型(abstract data type, ADT)是带有一组操作的一些对象的集合
表 ADT
形如 A0,A1,A2,...,AN−1 的表。表的大小为N,将大小为0的表成为空表(empty list)。称 Ai 后继 Ai−1 , Ai−1前驱 A_i$。
常用操作有:
prinList,MakeEmpty,find,insert,remove,findKth
数组表长度固定,insert(插入)和remove(移除)操作的最坏情况为线性开销O(n),开销较大。
简单链表
为避免插入和删除的线性开销,设计了一种不连续存储的表,移动其中一个不用去修改全体。
链表由一系列节点组成,这些节点不必在内存中相连,每一个节点均含有表允许和到包含钙元素后继元的节点的链,我们称之为next链,最后一个单元的next链引用为null。
- remove方法可以通过修改一个next引用来实现。
- insert方法需要使用new操作符从系统取得一个新节点,此后执行两次引用的调整。
一个节点同时拥有前后节点的链,陈伟双链表
Java Collectios API中的表
Collection接口
位于 java.util包中
public interface Collection<E> extends Iterable<E> {
int size();
boolean isEmpty();
void clear();
boolean contains(Object o);
boolean add(Objeat o);
boolean remove(Object o);
Iterator<E> iterator();
}
以上为Collection中一些重要的部分,方法名显而易见。
Collection接口扩展了Iterable接口。实现Iterable接口的类可以拥有for-each循环。
Iterator接口
实现Iterable接口的集合必须提供一个成为iterator的方法,此方法返回一个Iterator类型的对象
public interface Iterator<E> {
boolean hasNext;
E next();
void remove();
}
每个集合都可以创建一个实现Iterator接口的对象,并将当前位置在对象内部存储下来
- next 每次调用next方法都会得到集合下一项,第一次调用得到第一项。
- hasnext 判断是否存在下一项
- 下面,代码1会被编译器重写为代码2
//代码1
for(Object item:coll){
System.out.println(item);
}
//代码2
Iterator<Object> itr = coll.iterator();
while(itr.hasNext()){
Object item = itr.next();
System.out.println(item);
}
- 正在被迭代的集合不能改变其结构,即不能对它使用add,remove,clear方法。在使用被改变的集合迭代器时会抛出ConcurrentModificationException异常。
- 但是可以使用迭代器自己的remove方法,表示删除当前项,在下一次使用next方法之前只能调用一次remove方法。
List接口,ArrayList类,LinkedList类
list接口继承Collection接口。并在其基础上外加了一些方法。
public interface List<E> extends Collection<E>{
E get(int index);
E set(int index, E element);
void add(int index, E element);
E remove(int index);
ListIterator<E> listIterator(int index)
}
以上为一些比较重要的方法 index索引为 0~n-1
ListIterator为更复杂一些的迭代器。
List有两种比较流行的实现方式
- ArrayList 一种可增长数组
- 其优点在于对get和set花费常数时间
- 其缺点为remove和add的代价较高
- LinkedList 双链表
- 其优点为插入和删除开销较小,其提供了addFirst,removeFirst,addLast,removeLast,getFirst,getLast等有效的添加删除访问表两端的项。
- 其缺点为不容易做索引,set,get代价较高
ListIterator接口
ListIterator扩展了Iterator的功能
public interface ListIterator<E> extends Iterator<E>{
boolean hasPrevious();
E previous();
void add(E x);
E set(int index, E element);
}
部分重要方法
栈ADT
栈(stack)是限制插入和删除只能在表的末端的表。
末端叫叫做栈顶,基本的操作有push(进栈)和pop(出栈)。
栈又叫做LIFO(先进先出表)
ArrayList和Linkedlist都支持栈操作
所有它有两种流行的实现方式
- 链表实现
- 数组实现
栈的应用
平衡符号
检查语法错误,在纯文本写代码的情况下,经常会出现少写一个})]的情况,导致出现语法错误,一般的开发工具都支持语法检测,这里就会用到一个算法并用到栈,当然这只是一个简化的例子,实际的语法检测程序要复杂的多。
做一个空战。读入字符知道文件结尾。如果字符是一个开放符号({,(,[),则将其推入栈中,如果字符是一个封闭符号,则当栈空时报错。否则,将栈元素弹出。如果弹出的符号不变时对应的开放符号,则报错。在文件末尾,如果栈非空时报错。后缀表达式
在计算一个四则运算的时候,*和/的优先级要比+和-高,直接将我们日常所有的式子丢给计算机,他是无法直接理解的,比如 1+2*3+4/5,我们需要一个算法把它分解开再进行计算,例如后缀表达式,而相对应的我们日常所使用的叫做中缀表达式,当然也有前缀表达式。方法调用
队列ADT
像栈一样,队列(quene)也是表,然而使用队列时插入一段进行而删除则在另一端进行。叫做后进先出表(LIFO)
应用
有许多使用队列给出高效运行实际的算法,他们当中有些可以在图论中找到,我们在后面讨论他们。我们先举一些简单的例子
- 打印机任务
- 文件服务器