Java版数据结构与算法(二)

不能总放上一些概念和从别人那里转来的文章吧。。我会一直按着章节把原先的内容提炼出来,并把一些比较重要的代码附上~

第二章:表

(一)线性表

1.抽象数据类型(ADT):
        是带有一组操作的一些对象的集合。抽象数据类型是数学的抽象。
2.表ADT:
        表的简单数组实现,这种方式解决由于使用数组而产生的最严重的问题,即从历史上看为了使用一个数组,需要对表的大小进行估计。不过此方式在插入和删除的花费潜藏着巨大的开销,要看插入和删除发生在什么地方。因此,在这个方面,链表的优点则显得更为突出。
3.简单链表:
        为了避免插入和删除的线性开销,需要保证表可以不连续存储,否则表的每个部分都需要整体移动
    
链表由一系列结点组成,这些节点不必在内存中相连。每一个节点均含有表元素和到包含该元素后继元的节点的链(link)。称之为next链。最后一个单元的next链引用null。
因此,在实践中如果知道变动将要发生的地方,那么向链表插入或从链表中删除一项的操作并不需要移动很多的项,而是只涉及节点链的改变。

在经典链表中,每个节点均存储到其下一个节点的链,而拥有指向最后节点的链并不提供最后节点的前去节点的任何信息。

注意:


(二)集合类

4.Java Collections API

注意:add和remove,如果特定的集合不允许重复,add操作可能会失败
                                      如果要删除的项不在集合中,remove操作也可能会失败
Collection接口扩展了Interator接口。实现Iterator接口的哪些类可以拥有增强for循环,该循环施于这些类之上观察他们所有的项。

5.Iterator接口
定义:

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

此为例程~
使用Iterator的remove的两个优点(后面应该通过程序来验证)


6.List接口,ArrayList类和LinkedList类
   ListADT有两种流行的实现方式:
    1.ArrayList的优点:对get和set的调用花费常数时间,缺点是新项的插入和现有项的删除代价昂贵,除非变动发生在ArrayList的末尾。
    2.LinkedList的优点:提供了ListADT的双链表实现;新项的插入和现有项的删除代价的开销均很小。
        (双链表:每一个节点持有一个指向它在表中的前驱节点的链,即它的每个数据节点中都有两个指针,分别指向直接后继和直接前驱。)
ArrayList 采用的是数组形式来保存对象的,这种方式将对象放在连续的位置中,所以最大的缺点就是插入和删除时非常麻烦
LinkedList
采用的将对象存放在独立的空间中,而且在每个空间中还保存下一个链接的索引 但是缺点就是查找非常麻烦 要丛第一个索引开始。
ArrayList中有一个容器的概念,它表示的是基础数组的大小,在需要的时候,ArrayList可以自动增加其容量以保证它至少是表的大小。其中,trimToSize可以在所有ArrayList添加完成后使用来避免浪费空间。ArrayList的每次增长会预申请多一些的空间,是size()的1.5倍。而trimToSize的作用在于,删除多余的空间,使得预留元素的位置被删除。
7.remove方法对LinkedList的使用(将一个表中的所有偶数值的项进行删除)
   PS:此时,我们应当考虑的是 ArrayList、LinkedList 哪种方式更适合去完成这个任务,即使都可以实现,但我们应当选择一种更优的方法去完成。今后的重点不应放在如何去解决问题,而是更好的解决问题,寻找最优解。
相比较而言,ArrayList 是失败的,因为从一个ArrayList的几乎任何地方进行删除都是昂贵的操作(因为其以数组形式保存对象,而对象是连续的,当进行删除插入操作时,需要在进行操作的位置把后面的元素依次移动来实现,十分低效)此时,LinkedList应该会是更好的选择,因为从已知位置的删除操作都可以重新安排某些链而被有效的完成。
方法一:
public static void removeNum(List<Integer> list){ 
 int i = 0; 
 while(i < list.size()){   //去掉偶数 
 if( list.get(i) % 2 == 0 ){ 
 list.remove(i); 
 } 
 else i++; 
 } 
} //删除表中的偶数,算法对任何类型的表都是二次的 2015/01/20 11:37

方法二(当迭代器遍历到一个偶数时,我们可以用迭代器来删除这个偶数):
public static void removNum(List<Integer> list){
    Iterator<Integer> iterator = list.iterator();
    while( iterator.hasNext()){
    if( iterator.next() % 2 == 0){
        iterator.remove();
    }
}
因此,对于LinkedList而言,花费的是线性时间;对于ArrayList而言,必须要进行数组的移动。
在说明两者实现之前,想再次总结性的提一下这两者间的区别
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 
2.对于随机访问get和set,ArrayList优于LinkedList,ArrayList可以随机定位,而LinkedList要移动指针一步一步的移动到节点处。(参考数组与链表来思考)
3.对于新增和删除操作add和remove,LinedList比较占优势,只需要对指针进行修改即可,而 ArrayList要移动数据来填补被删除的对象的空间。
8.ArrayList类和LinkedList类的实现


通过获取一个新节点,然后按照指示的顺序改变指针而完成一个双链表的插入操作
Node newNode = new Node(x , p.prev , p);
p.prev = p.prev.next = newNode;

当提及两者在性能上的差别,以及什么情况下去选择何种方法来完成任务。在这里,我们在CSDN上面借鉴一篇文章,地址:http://blog.csdn.net/wuchuanpingstone/article/details/6678653
不过不得不说他的代码没有经过测试,不过还是很能说明问题的(而且劝大家最好不要测试,因为会使电脑变卡,如果想要测试的话,可以把最先设定的集合空间改一下,不过也不能太小,否则无法说明问题)。
其中部分方法我在这里做出解释:
1.binarySearch()
返回值:如果它包含在数组中,则返回搜索键的索引;否则返回(-(插入点) - 1) 
    插入点:被定义为将键插入数组的那一点:即第一个大于此键的。
    元素索引,如果数组中的所有元素都小于指定的键,则为 a.length。注意,这保证了当且仅当此键被找到时,返回的值将 >= 0。否则返回 (-(插入点) - 1)这句话要注意:要是查询的的值小于数组里面的最小值那么结果(-(0)-1结果就是-1),如果查询的值大于数组里面的最大值。那么结果就是(-(它的索引值)-1结果就是-(1+索引值))
binarySearch(a,1,5,8)表示在a中的a[1]至a[5]中用二分法找8这个数但是在这中没有比8大的数,也没有8。所以实际找到的是a[5],也就是6,因为没有找到所以在前面加负号。
2.System.currentTimeMillis()
    获取系统当前时间。
3.Arrays.asList()
 * (1) 该方法对于基本数据类型的数组支持并不好,当数组是基本数据类型时不建议使用。
 * (2) 当使用asList()方法时,数组就和列表链接在一起了。
 *     当更新其中之一时,另一个将自动获得更新。 
 *     注意:仅仅针对对象数组类型,基本数据类型数组不具备该特性。
 * (3) asList得到的数组是的没有add和remove方法的。 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值