java数据结构

来源:互联网 发布:mathcad 矩阵运算 编辑:程序博客网 时间:2024/05/03 23:03

数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法索引技术有关。

数据结构分为线性的和非线性的

线性:必须有唯一的第一个节点和最后一个节点,其他节点只有唯一的前驱和后驱

常用的线性结构有:线性表(包括顺序表和链表),栈,队列,双队列,数组,串。

关于广义表,是一种非线性的数据结构。

常见的非线性结构有:二维数组,多维数组,广义表,树(二叉树等),图(网等)。


集合

线性结构:线性表、栈、单双队列、数组、串

树形结构:一对多的一种树形结构、根节点没有前驱,叶子节点没有孩子节点。可表示从属关系、并列关系

图形结构:元素之间是相互的,其他结构都有明确的条件、但是图形结构没有,任意两个都可以相关联


Collection接口   
  Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements)。一些 Collection允许相同的元素而另一些不行。一些能排序而另一些不行。Java  SDK不提供直接继承自Collection的 类,Java  SDK提供的类都是继承自Collection的“子接口”如List和Set。   
  所有实现Collection接口的类都必须提供两个标准的构造函数:无参数的构造函数用于创建一个空的Collection,有一个 Collection参数的构造函数用于创建一个新的Collection,这个新的Collection与传入的Collection有相同的元素。后 一个构造函数允许用户复制一个Collection。   
  如何遍历Collection中的每一个元素?不论Collection的实际类型如何,它都支持一个iterator()的方法,该方法返回一个迭代子,使用该迭代子即可逐一访问Collection中每一个元素。典型的用法如下:   
    Iterator  it  =  collection.iterator();  //  获得一个迭代子   
    while(it.hasNext())  {   
      Object  obj  =  it.next();  //  得到下一个元素   
    }   
  由Collection接口派生的两个接口是List和Set。   

 集合类的根接口Collection

   Collection接口是所有集合类的根类型。它的一个主要的接口方法是:

boolean add(Object c)

   add()方法将添加一个新元素。注意这个方法会返回一个boolean,但是返回值不是表示添加成功与否。仔细阅读doc可以看到,Collection规定:如果一个集合拒绝添加这个元素,无论任何原因,都必须抛出异常。这个返回值表示的意义是add()方法执行后,集合的内容是否改变了(就是元素有无数量,位置等变化),这是由具体类实现的。即:如果方法出错,总会抛出异常;返回值仅仅表示该方法执行后这个Collection的内容有无变化。

   类似的还有:

boolean addAll(Collection c);

boolean remove(Object o);

boolean removeAll(Collection c);

boolean remainAll(Collection c);

   Object[] toArray()方法很简单,把集合转换成数组返回。Object[] toArray(Object[] a)方法就有点复杂了,首先,返回的Object[]仍然是把集合的所有元素变成的数组,但是类型和参数a的类型是相同的,比如执行:

String[] o = (String[])c.toArray(new String[0]);

  得到的o实际类型是String[]。

   其次,如果参数a的大小装不下集合的所有元素,返回的将是一个新的数组。如果参数a的大小能装下集合的所有元素,则返回的还是a,但a的内容用集合的元素来填充。尤其要注意的是,如果a的大小比集合元素的个数还多,a后面的部分全部被置为null。

用Iterator模式实现遍历集合

 Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。

 例如,如果没有使用Iterator,遍历一个数组的方法是使用索引:

for(int i=0; i<array.size(); i++) { ... get(i) ... }
 而访问一个链表(LinkedList)又必须使用while循环:
while((e=e.next())!=null) { ... e.data() ... }

以上两种方法是我们都必须知道结合的内部结构、代码和集合本身是紧耦合,无法将访问逻辑从集合类和客户端代码分离开来,每一个集合都必须对应一种遍历方法、我们无法重用。

假如:需要把arrayList改成LinkedList,那么原来的代码必须完全重写

为了解决这些个问题,Iterator模式用一种相同的逻辑来遍历集合。Iterator由集合类通过工厂方法生成,因此,它知道如何遍历整个集合。

每一种集合类返回的Iterator具体类型可能不同,Array可能返回ArrayIterator,Set可能返回SetIterator,Tree可能返回TreeIterator,但是它们都实现了Iterator接口,因此,客户端不关心到底是哪种Iterator,它只需要获得这个Iterator接口即可,这就是面向对象的威力。

List接口   
  List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。   
和下面要提到的Set不同,List允许有相同的元素。   
  除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个 ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,双向访问,还提供了一个方法来获取从列表中指定位置开始的列表迭代器, 还能向前或向后遍历。   
  实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。   
  ArrayList类   
  ArrayList实现了可变大小的数组。  
        它允许所有元素,包括null,   size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。   
  每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法 并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。  

ps:ArrayList非同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:   

    List  list  =  Collections.synchronizedList(new  ArrayList(...));   
  非同步的,获得的iterator对象是快速失败的,也就是只有通过iterator才可以移除或者添加元素,期间通过list改变结构的话,报异常ConcurrentModificationException

LinkedList类   
  LinkedList实现了List接口(链接列表的实现),允许null元素。此外LinkedList提供额外的get,remove,insert方法在 LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。   
  ArrayList一样,LinkedList也是非同步的(unsynchronized)。   

Vector类   
  Vector非常类似ArrayList(对象数组),但是Vector是同步的。由Vector创建的Iterator,虽然和ArrayList创建的 Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例 如,添加或删除了一些元素),这时调用Iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该 异常。

Stack  类   
  Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop 方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。   


 Set接口   
  Set是一种不包含重复的元素的Collection,即任意的两个元素e1和e2都有e1.equals(e2)=false,Set最多有一个null元素。  Set实现的基础是Map(HashMap);
  很明显,Set的构造函数有一个约束条件,传入的Collection参数不能包含重复的元素。   
  请注意:必须小心操作可变对象(Mutable  Object)。如果一个Set中的可变元素改变了自身状态导致Object.equals(Object)=true将导致一些问题。   

SortedSet接口
关于元素的总排序的set继承set通常在创建有序 set 时提供的 Comparator 进行排序。该 set 的迭代器将按元素升序遍历 set
EnumSet抽象类
集成枚举Enum,EnumSet也是非同步的、基本所有操作都是固定时间的,可能比HashSet快,枚举 set 中所有键都必须来自单个枚举类型。
HashSet类
实现set接口,它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素,非同步的
TreeSet类
基于TreeMap的NavigableSet 实现,使用元素的自然顺序对元素排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法,非同步的。
 Set 对象本身是没有顺序的,Set首先保证元素的唯一性
LinkedHashSet 和 TreeSet具有顺序。
Map接口   
  请注意,Map没有继承Collection接口,Map提供key到value的映射。一个Map中不能包含相同的key,每个key只能映射一个 value。Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。   
 某些映射实现可明确保证其顺序,如TreeMap 类;另一些映射实现则不保证顺序,如HashMap 类。
Hashtable类   
  Hashtable继承Map接口,实现一个key-value映射的哈希表。任何非空(non-null)的对象都可作为key或者value。   
  添加数据使用put(key,  value),取出数据使用get(key),这两个基本操作的时间开销为常数。   
Hashtable通过initial  capacity和load  factor两个参数调整性能。通常缺省的 load  factor  0.75较好地实现了时间和空间的均衡。增大load  factor可以节省空间但相应的查找时间将增大,这会影响像 get和put这样的操作。   
使用Hashtable的简单示例如下,将1,2,3放到Hashtable中,他们的key分别是”one”,”two”,”three”:   
    Hashtable  numbers  =  new  Hashtable();   
    numbers.put(“one”,  new  Integer(1));   
    numbers.put(“two”,  new  Integer(2));   
    numbers.put(“three”,  new  Integer(3));   
  要取出一个数,比如2,用相应的key:   
    Integer  n  =  (Integer)numbers.get(“two”);   
    System.out.println(“two  =  ”  +  n);   
  由于作为key的对象将通过计算其散列函数来确定与之对应的value的位置,因此任何作为key的对象都必须实现hashCode和equals方 法。hashCode和equals方法继承自根类Object,如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相 同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同,如 果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希 表的操作。   
  如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和hashCode方法,而不要只写其中一个。   
  Hashtable是同步的。   
  
HashMap类   
  HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null  value和 null  key。,但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和 HashMap的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load  factor过 低。   
  
WeakHashMap类   
  WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。

TreeMap类

是非同步的,有序的根据其键的自然排序进行排序

0 0
原创粉丝点击