码迷,mamicode.com
首页 > 其他好文 > 详细

第三章节 表,栈,队列

时间:2015-05-10 22:15:49      阅读:121      评论:0      收藏:0      [点我收藏+]

标签:

抽象数据类型(abstract data type ADT)是带有一组操作的对象的集合。

一、 表ADT

  • 表的数组实现 

数组实现时,插入和删除的花费可能会比较大,这样要看操作发生在什么地方。最坏情况如,在0处插入,和删除第一个元素。此时为O(N)。

如果表是通过在高端插入,其后只发生对数组的查找访问(findKth),则数组很适合。否则,不是。

  • 简单链表

为了避免插入和删除的线性开销,应该使表可以不连续存储。否则表的每个部分都可能要整体移动。这样就是链表。

findKth(i)要花费O(i)的时间,但是在实践中这是比较保守的情况 ,因为findKth常常以排序后的方式进行,如findkth(1),

findkth(2),...都是一次性的完成的。

二、Collections API中的表

Collections API中有一些普通的的数据结构的实现,表ADT中其中的一部分。

  • Collections 接口
public interface Collection<AnyType> extends Iterable <Anytype>{
    int size();
    boolean isEmpty();
    void clear ();
    boolean contains(Anytype x );
    boolean add(Anytype x);
    boolean remove (Anytype x );
    Iterator <Anytype> interator ();
}

collection接口扩展了Iterable 接口,实现了Iterable接口的类有增强的for循环。

  • Iterator接口

实现了Iterable 接口的集合一定要有一个iterator的方法,这个方法返回一个Iterator类型的对象 。定义如下

public interface Iterator <Anytype> {
    boolean hasNext ();
    Anytype next ();
    void remove ();//删除next最新返回的项
}

思路是,通过iterator 方法,每个集合可以创建并返回客户一个实现了Iterator接口的对象,并将当前位置的概念在对象内部存储下来。

 当编译器遇到用于Iterator对象的增强的for循环时,它用对iterator方法的那些 调用 代替增强的for循环以得到一个 Iterator对象 ,然后调用 next/ hasNext .

也就是说,下面的程序将会被编译器重写 。

for (Anytype item : collection )
    system.out.println(item);
}

//重写为
Iterator <Anytype> itr = collection.iterator();
while (itr.hasNext()){
    Anytype item = itr.next();
    System.out.println(item);
}

Iterator的remove()方法优点 :

Collection的remove()一定要先找到被删除的项。如我们要每隔一项删除一个,用迭代器更好。

当直接使用Iterator(而不是通过一个增强for循环间接使用时)一个重要的是:

如果正在被迭代的集合结构正在发生变化 (如add, remove , clear 方法)那么迭代器就不再合法,会有ConcurrentModificationException。

然而如果迭代器调用 的是自己的remove方法,则是没有问题的,这个也是我们更愿意用迭代 器的remove方法的第二个原因。

  • List接口、ArrayList接口、LinkedList接口

List继承了Collection接口。

public interface List<Anytype> extends Collection<Anytype>{
    Anytype get(int idx );
    Anytype set(int idx ,Anytype x );
    void add (int idx ,Antype x );
    void remove (int idx );
    
    ListIterator<Anytype> listIterator(int pos );
}

 List ADT 有两种实现方式 :

ArrayList:可增长的数组的实现

  优点:get set 是常数时间

  缺点:新插入的项和删除代价高,除非在ArrayList的末尾进行。

LikedList:双链表的实现  

  优点:insert /remove开销小。

  缺点:不容易 做索引,因此get 开销大,除非 get 操作是对接口两个端点的。(可以考虑使用 iterator )

对搜索来说,ArrayList/ LinkedList都是低效的,对 Collections 的contains / remove两个方法,它们都要花费线性时间。

  • remove方法对LinkedList的使用

对ArrayList,肯定是不行,因为remove代价很大。

分析 LinkedList。

方案1 :

public static void removeEven( List <Integer> lst){
    int i =0;
    while (i<lst.size()){
        if (lst.get(i)%2==0){
            lst.remove(i);
        }else {
            i++;
        }
    }
}

上面有两个问题:

1. get效率不高,因此上面的要花费二次时间。

2. remove 调用 同样开销大,因为找到位置 i 代价很大。

方案2:

for (Integer x : lst)
    if (x%2==0)
        lst.remove(x);  //这里是collection的remove 

这里我们不使用get  而是使用迭代器遍历,这是高效的。但是却是Collection的remove,这个一定要重新搜索,所以不是高效的,要

线性时间。

最重要的是,程序 会的异常,因为当一个项被删除(collection的 remove)的时候,迭代器的使用是非法的。

方案3:

Iterator<Integer> itr = lst.iterator();

while (itr.hasNext ()){
    if (itr.next()%2==0)
        itr.remove() ;
}
} 

我们使用迭代 器来删除 。整个程序只要线性时间,而不是二次时间。

  • ArrayList的实现 
  • LinkedList的实现 

三、栈ADT 

四、队列ADT 

 

第三章节 表,栈,队列

标签:

原文地址:http://www.cnblogs.com/chuiyuan/p/4492957.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!