抽象数据类型ADT是带有一组操作的对象的集合,诸如表、图以及它们各自的操作一起形成的对象等等
本章将讨论基于表ADT的实现,主要是数组与链表
是否重复:可重复存放的
是否有序:数组是无序的,链表是按插入顺序排序的
1 表ADT
大小为N的表 : A0,A1,A2,A3,……,A(N-1)
其中Ai 是 A(i-1)的后继元,A(i-1)是 Ai 的前继元
对表的实现主要是数组和链表
表是可重复的、无序或按插入顺序排列的。
1.1 数组
数组是由固定容量创建的,用来实现表ADT,不赘述。
1.2 链表
链表由一系列节点组成,这些节点不必在内存中相连。
1.2.1 单向链表
每一个节点含有表元素、指向该元素后继元节点的引用(next)
最后一个单元的next指向null
1.2.2 双向链表
每一个节点含有表元素、指向该元素后继元节点的引用(next)、指向该元素前继元节点的引用(prev)
最后一个单元的next指向null
第一个单元的prev指向next
1.2.3 编程实现
此处以双向链表为
1 首先定义节点类,存放数据、前节点、后节点
private class Node<T>{ //节点
public T data;
public Node<T> prev;
public Node<T> next;
public Node(T t , Node<T> p, Node<T> n) {
this.data = t;
this.prev = p;
this.next = n;
}
}
2 在链表类中,我们需要定义两个虚拟的节点:一个首节点作为一个链表的开头,一个尾节点作为链表的结尾
初始化时有首节点.prev = null ; 尾节点.next = null; 首节点.next = 尾节点; 尾节点.prev = 首节点;
public class MyLinkedList<T> {
private int size;
private Node<T> beginNode;
private Node<T> endNode;
public MyLinkedList(){
this.size = 0;
this.beginNode = new Node<T>(null,null,null);//Data null
this.endNode = new Node<T>(null,beginNode,null);
this.beginNode.next = this.endNode;
}
具体代码实现见GitHub
2 Collection API
2.1 基于数组:ArrayList、Vector(Stack)
2.1.1 ArrayList
ArrayList 和 Vector的唯一区别在于,Vector类中的方法都是带有synchronized关键字的,故用于多线程下线程安全,ArrayList类用于单线程下
2.1.2 Stack(栈ADT)
栈ADT是限制插入和删除只能在一个位置的特殊表,表头入栈,表头出栈,栈的顶端(top),具有后进先出(LIFO)的特性
Stack是Vector类的子类,基于数组实现,同样在List接口下,实现栈ADT
对栈的基本操作,同样Stack也是线程安全的
public E push(E item) { // 1 把元素压入栈顶
}
public synchronized E pop() { // 2 返回栈顶的元素,并把这个元素删除
}
public synchronized E peek() { // 3 仅仅返回栈顶元素,不改变栈的结构
}
public boolean empty() { // 4 是否为空栈
}
经典案例:
1 检查符号是否成对
2 后缀表达式
3 中缀转后缀
4 主方法调用其他方法时位置信息的存储
2.2 基于链表:LInkedList(实现List Queue两个接口)
2.2.1 队列ADT(Queue)
队列ADT和栈一样,同样是一种特殊的表ADT,队列要求插入在一端而删除在另外一端,表末入列,表头出列,具有先进先出(FIFO)的特性
2.2.2 LinkedList
LinkedLIst是一个比较特殊的类
基于双链表ADT实现
实现了List和Queue两种接口
在LinkedList类内部定义了push、pop等函数
所以它可以
当做一个List使用
List list = new LinkedList();
list.add(12);
当做一个队列使用
1 Queue中都定义了两种返回方式的方法(a抛出异常b返回特定值)
向队列中加入元素:a : add() b : offer()
返回队首元素,但不删除该元素:a : elelment() b : peek()
从队首移除一个元素:a: remove() b : poll()
// 向上转型Queue接口,调用Queue接口的方法
Queue list1 = new LinkedList();
list1.offer(123);//push
list1.element();
list1.remove();
2 我们还可以使用LInkedList本身自定义方法实现队列
表末入栈,表头出栈,先进先出
public void offer (Object o){//进队,在表末入列
list.addLast(o);// addLast 与 add 无异
}
public Object remove() {//出队,在表头出列
return list.removeFirst();
}
public Object element() {
return list.getFirst();
}
当做一个栈使用
LinkedList本身实现了addFirst(),getFirst(),removeFirst()方法用来做当push,pop, peek方法
表头入栈出栈,先进后出
public void push(String name){ //表头入栈
linkedList.addFirst(name);
}
/** (即取出链表linkedList的第一个元素) /
public String peek(){ // 表头出栈
return linkedList.getFirst();
}
/** (即移出linkedList的第一个元素) /
public String pop(){
return linkedList.removeFirst();
}