集合框架和数据结构

来源:互联网 发布:网络覆盖 编辑:程序博客网 时间:2024/06/02 02:28
集合框架学习心得 - Garfield - 张广辉的博客

  
1,    ArrayList 和LinkList的差别就在于数组与链表的差别,数组对于给定索引index进行数据检索比较容易,时间为O(1),而对于插入和删除操作时间为O(n),即使在末尾进行插入,可能会因为容量不足而需要扩容需要大量时间。数组的末尾插入的加权时间为O(1)。而链表进行检索时,需要从链表的header处开始进行指针移动,时间为O(n),而单纯的插入和删除时间较短,为O(1)。



4,    初始时,iterator指向第0个元素.它的next()方法先返回当前值,再跳转到下一个元素。他的previous方法,先回到上一个元素,在返回上一个元素。
5,    递归和迭代基本是可以相互转换,递归的原理是拿空间换时间,因为递归的过程会产生大量的栈帧,但时间复杂度要约为减少。
6,    Map的key都是以set方式存储,value是以list,map的迭代器。HashMap中的entrySet()、keySet()、values()等方法都使用到了迭代器Iterator,其中entrySet()返回一个set集合,集合中存放map,即set<entry.map<key,value>>.
7,    类中重写equals方法时需要重写hashcode方法。
(1)当obj1.equals(obj2)为true时,obj1.hashCode() == obj2.hashCode()必须为true 
(2)当obj1.hashCode() == obj2.hashCode()为false时,obj1.equals(obj2)必须为false
hashcode也可以表示两个对象是否相等,如果不重写hashcode,当两个equals的对象存储在哈希表当中时,明明对象equals,却存在哈希数组的两个位置,这样哈希中引起错误。也就是说,当你用其中的一个对象作为键保存到hash中,再以equals的另一个对象作为键值去查找他们的时候,则根本找不到。

hashcode的重写方式:比如学生类,如果重写equals的时候以学生的ID是否相等作为学生是否相等的依据时,那么重写hashcode方法时,就可以返回学生ID的hashcode,这样两个学生的hashcode也相等了。

9,    Collections类中的sort为归并排序,只能接受序列,不能为基础类型;Arrays类中的sort为快排序,可以接受数组和序列。Collections.sort() 对列表进行排序,列表中的元素必须实现compareable接口。如果没有实现compareable,可以在第二个参数处传递一个实现了comparabtor的对象进去。Arrays.sort还可以排序数组。
10,一致性哈希
http://blog.sina.com.cn/s/blog_3fde8252010147j5.html
http://blog.csdn.net/cywosp/article/details/23397179

11,数组:创建数组时,如果类型为引用类型,则数组里保存的是对象的引用,所以并不会引起classload。
新建数组时必须要指定长度,除非为其初始化。新建二维数组必须要指定其二维的长度,二维数组中的元素实际就为一维数组。
12,set:sortset接口扩展了set,除了不能重复(equals)外,让set中的对象以升序存放,存入set的对象必须实现compareable接口,代表为treeset。而hashset无序。
13,hashmap的原理与不足。
原理:采用一个数组,数组里存放的是entry.map<key,value>,数组的索引为index,index=key.hashcode()%tab.length;
 http://www.cnblogs.com/hzmark/archive/2012/12/24/HashMap.html

resize方法:使用无参构造HashMap时,初始数组大小为INIT_SIZE=16,LOAD_FACTOR为0.75,当存入的键值对的个数大于INIT_SIZE*LOAD_FACTOR时,执行resize方法,将数组扩容2倍并将原数组键值对重新哈希。
集合框架和数据结构 - Garfield - 张广辉的博客
在ReHash的过程后,HashMap的数组的内存可能与该对象成员变量不在一块区域,访问速度下降;产生大量垃圾,延长了gc。所以应尽量减少使用无参构造,而尽量设定数组初值。另外在并发情况下,该过程非常容易产生链表的死循环问题。
 
 
不足:元素的无序性(treemap有序),不能并发,table扩容时需要重新hash。

自己设计hashmap需要注意:1,均匀散列,让所有键值尽可能均匀分布,hash = hash(key.hashCode()); 两次哈希,有一种折叠法(64位数,高32位与低32位异或);2,防止值得冲突(key1!=key2,key1.hashcode==key2.hashcode),采用链式结构。3,put方法时,对table进行扩容时,要注意刷新取余的值为新的长度,重新hash找索引。从链表头插入
 
使hashmap线程同步的方式
http://www.ibm.com/developerworks/cn/java/j-jtp07233/
 
java实现简单的hash table(默写)
http://blog.csdn.net/liuhongxingrs/article/details/2942432

 
14,HashMap和Hashtable有什么区别?
  • HashMap和Hashtable都实现了Map接口,因此很多特性非常相似。但是,他们有以下不同点:
  • HashMap允许键和值是null,而Hashtable不允许键或者值是null;table[0]中的链表是否包含key为null的元素;
  • Hashtable是同步的,而HashMap不是。因此,HashMap更适合于单线程环境,而Hashtable适合于多线程环境。
  • HashMap提供了可供应用迭代的键的集合,因此,HashMap是快速失败的。另一方面,Hashtable提供了对键的列举(Enumeration)。
    • 一般认为Hashtable是一个遗留的类。
15,集合中不允许存放基础数据类型,存放对象的引用,而数组可以。集合和数组均可以存放不同数据类型的对象。


17,树:二叉搜索树:右孩子(右子树所有节点)>父亲>左孩子(左子树所有节点);查询和插入时,从根节点开始,大于根访问右,小于根访问左,最后在叶节点插入。删除时,如果不是叶子节点需要重构树。策略为先把该删除的删除,再从后继元素中找一个来代替。平均时间均为为O(logn),最差时间为O(n),取决于树的高度。

树的旋转可以减小树的高度:单旋转,双旋转(先让自己的子树绕孩子旋转,再绕自身旋转)。

AVL树和红黑树高度均为logN,可以在O(log n)时间内做查找,插入和删除等操作。AVL树左右子树高度最多相差1,左右子树均为AVL。

红黑树与AVL的比较:

AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多;
红黑是用非严格的平衡来换取增删节点时候旋转次数的降低;
说它不严格是因为它不是严格控制左、右子树高度或节点数之差小于等于1。
但红黑树高度依然是平均log(n),且最坏情况高度不会超过2log(n)。
所以简单说,如果你的应用中,搜索的次数远远大于插入和删除,那么选择AVL,如果搜索,插入删除次数几乎差不多,应该选择RB。

 

TreeMap的底层实现 http://www.cnblogs.com/yydcdut/p/4009201.html    红黑树在进行插入和删除后要进行旋转和着色调整。

18,堆是一棵完全二叉树,孩子的值大于父亲,i节点的两个孩子的索引为2i+1和2i+2.

堆调整:将堆中的某个元素与其父节点交换,直到满足条件为止。推排序就是不断进行堆调整,不断取走跟元素。



20 Enumeration接口和Iterator接口的区别有哪些?

Enumeration速度是Iterator的2倍,同时占用更少的内存。但是,Iterator远远比Enumeration安全,因为其他线程不能够修改正在被iterator遍历的集合里面的对象,否则会抛出异常。同时,Iterator允许调用者删除底层集合里面的元素,这对Enumeration来说是不可能的。


21,静态链表
动态链表就是通常所用的链表,是用申请内存函数动态申请内存的,所以在链表的长度上没有限制。动态链表因为是动态申请内存的,所以每个节点的物理地址不连续,要通过指针来顺序访问。静态链表是用数组实现的,是顺序的存储结构,在物理地址上是连续的,与动态链表唯一的不同在于需要预先分配大小,且不能扩容。但在插入、删除时也是通过修改指针域来实现的,与动态链表相同。
  1. #define MAXSIZE 100;    
  2. typedef struct{    
  3.   ElemType data;    
  4.   int cur;    
  5. }component,SLinkList[MAXSIZE];  


22,广义表:
广义表中的元素可以是基本数据元素,也可以是一个广义表。如果全是基本数据元素,则就是线性表。
非空广义表的尾元素一定一个广义表。
0 0
原创粉丝点击