List ADT的两种实现方式

原创 2017年01月03日 03:00:46

ArrayList类和LinkedList类

List ADT 有两种流行的实现方式,ArrayList类与LinkedList类。

ArrayList类提供了List ADT 的一种可增长数组的实现。使用ArrayList的优点在于,对get和set的调用花费常数时间。缺点是对于新项的插入和现有项的删除代价昂贵。除非更改是发生在末端的。

LinkedList类则提供了List ADT 的双向链表的实现。使用LinkedList的优点在于,新项的插入和现有项的删除开销很小,缺点则是get和set的开销很大,除非接近端点。

下面用一些方法来使结论更明显:

public static void makeList(List<Integer> lst, int N) {
    lst.clear();
    for (int i = 0; i < N; i++) {
        lst.add(i);
    }
}
Type Time
ArrayList O(N)
LinkedList O(N)

无论ArrayList还是LinkedList,每次调用add都是在表的末端进行,所以都是O(N)


public static void add(List<Integer> lst, int N) {
    lst.clear();
    for (int i = 0; i < N; i++) {
        lst.add(0, i);
    }
}
Type Time
ArrayList O(N2)
LinkedList O(N)

public static int sum(List<Integer> lst, int N) {
    int total = 0;
    for (int i = 0; i < N; i++) {
        total += lst.get(i);
    }
    return total;
}
Type Time
ArrayList O(N)
LinkedList O(N2)

这里特别要说明下的是,如果改用增强for循环,那么两者的时间就都是O(N),因为迭代器将有效地从一项到下一项推进。

迭代器

作为一个例子,我们提供一个例程,将一个表中所有具有偶数值的项删除。

当遇到表中的项时,将其从表中删除的算法有几种可能的想法,当然我们有兴趣的是写一个干净的避免拷贝的表,并在遇到偶数值时就将它们删除。

对于ArrayList这就是一个失败的策略,因为对ArrayList的任意一个地方进行删除都是效率很低的,但在LinkedList中却有希望,因为从已知位置删除项可以通过修改链而完成。

想法1:

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

在一个ArrayList上,remove的效率是很低的,程序的花费是二次时间。
在LinkedList上,由于对get调用效率的不高(每次寻找都得从两端开始),所以程序的花费是二次时间。

想法2:

public static void removeEvenVer2(List<Integer> lst) {
    for (Integer x : lst) {
        if (x % 2 == 0) {
            lst.remove(x);
        }
    }
}

这个想法试图矫正上一种思路,不再使用get而是用iterator遍历表,这显然是高效率的。但是使用了Collection的remove方法,会抛出一个异常。
想法3:

public static void removeEvenVer3(List<Integer> lst) {
    Iterator<Integer> iterator = lst.iterator();
    while (iterator.hasNext()) {
        if (iterator.next() % 2 == 0) {
            iterator.remove();
        }
    }
}

这是一个成功的想法,对于一个LinkedList,迭代器的remove方法的时间花费是线性的,因为迭代器位于被删除的节点上,而对于ArrayList,始终要在remove后进行数组的移动,仍然花费二次时间。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

查询字符串中字母的个数(两种实现方式1,list与set集合 2,map集合)

题目: 取出一个字符串中字母出现的次数。如:字符串:"abcde%^kka27qoq" ,输出格式为:a(2)b(1)k(2)... 第一种方式(set和list结合使用): package ith...

Skip list -- 跳跃表的插入删除搜索等ADT操作的实现与测试

源代码如下: #include #include #define lgNmax 5 typedef char Key; struct Item{Key key;}; typede...

【ionic+angularjs】$ionicScrollDelegate list列表行记录定位的两种方式

为什么要定位? 在访问带有列表的页面,一般会点击列表中某行记录,访问其详情页面,点击返回后回到列表页面,若不进行定位,那么用户需要重新滚动直到找到刚才点击的行记录,体验不好。那么返回时定位可以将...

List集合中两种遍历方式

遍历List集合中的元素的方法有两种: 第一种:利用迭代器遍历 代码1: // 迭代器 Iterator it=list.iterator(); while(it.hasNext()) {...

Collections.sort方法对list排序的两种方式

Collections.sort( )分为两部分,一部分为排序规则,一部分为排序算法 。 规则用来判断对象,算法则考虑如何进行排序 对于自定义对象,sort()不知道规则,所以无法比较,这种情况下一定...

Collections.sort( )方法对list排序的两种方式

转自:http://blog.csdn.net/memewry/article/details/7907012 Collections.sort( )分为两部分,一部分为排序规则,一部分为排...

访问www首页不跳转三级域名的两种方式 (struts welcome-file-list index.action问题)

在工程发布的时候,会遇到直接访问www域名,其中需要action请求数据,访问不到内容的情况,比方: 1.访问www.xxx.com 无法访问 2.访问www.xxx.com 做跳转,url跳转到了w...
  • saife
  • saife
  • 2015-01-19 12:55
  • 985

将List转成树的两种方式(递归、循环)

在做目录树的时候通常是将一个目录存在数据库的List全部返回来,再根据节点id和parentId组装成一颗树,这里切忌使用递归查询的方式实现。List转成Tree有两种方式,一种是常用的递归,一种是双...

Collections.sort方法对list的两种排序方式

Collections.sort方法对list的两种排序方式 Collections.sort( )分为两种,一种方式是排序规则,另一种方式是排序算法 。 其中规则是用来判断对象而算法...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)