于吉吉的技術博客

          建造高性能門戶網

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            65 隨筆 :: 6 文章 :: 149 評論 :: 0 Trackbacks
          看一段set的簡單應用代碼

                  Set<String> set = new HashSet<String>();
                  String a 
          = "1",b = "2",c = "1",d = "3",e = "2";
                  set.add(a);
                  set.add(b);
                  set.add(c);
                  set.add(d);
                  set.add(e);
                  
                  Iterator it 
          = set.iterator();
                  
          while(it.hasNext()){
                      String s 
          = (String)it.next();
                      System.out.print(s
          +",");
                  }
                  System.out.println(
          "一共有對象:"+set.size()+""); //打印結果是:3,2,1,一共有對象:3個

          我們都知道Set是一種最簡單的集合,對象的排序無特定的規則,集合里面存放的是對象的引用,所以沒有重復的對象,在上面的代碼中,程序創建了a、b、c、d、e五個變量,其中a和c,b和e所引用的字符串是一致的,然后向set添加了這5個變量。打印出來的size()只有3個,實際上向集合加入的只有3個對象,在執行Set的add()方法時已經進行了判斷這個對象是否存在于集合,如果對象已經存在則不繼續執行。


          Set的接口有兩個實現類,HashSet和TreeSet,HashSet是按照哈希算法來進行存取集合中的對象,存取速度比較快,TreeSet類顯示了SortedSet接口,具有排序功能

          HashSet
          HashSet是按照哈希算法來存取集合中的對象,具有很好的存取和查找性能,當向集合中加入一個對象時,HashSet會調用對象的hashCode()方法來獲取哈希碼,然后根據這個哈希嗎來計算對象在集合中的存放位置。
          在Object類中定義了hashCode()和equal(),equal()是按照內存地址比較對象是否相同,如果object1.equal(object1)w為true時,則表明了object1和object2變量實際上引用了同一個對象,那么object1和object2的哈希碼也是肯定相同。
          稍微的看看HashSet的源碼

          public class HashSet<E>
              
          extends AbstractSet<E>
              
          implements Set<E>, Cloneable, java.io.Serializable
          {

              
          private transient HashMap<E,Object> map;
              
          private static final Object PRESENT = new Object();
                  
          public HashSet() {
                  map 
          = new HashMap<E,Object>();
              }

             
          public boolean add(E e) {
                  
          return map.put(e, PRESENT)==null;
              }
          }

          public class HashMap<K,V>
              
          extends AbstractMap<K,V>
              
          implements Map<K,V>, Cloneable, Serializable
          {

              
          public V put(K key, V value) {
                  
          if (key == null)
                      
          return putForNullKey(value);
                  
          int hash = hash(key.hashCode());
                  
          int i = indexFor(hash, table.length);
                  
          for (Entry<K,V> e = table[i]; e != null; e = e.next) {
                      Object k;
                      
          if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                          V oldValue 
          = e.value;
                          e.value 
          = value;
                          e.recordAccess(
          this);
                          
          return oldValue;
                      }
                  }

                  modCount
          ++;
                  addEntry(hash, key, value, i);
                  
          return null;
              }

          }

          我們會發現我們調用Set的add()方法其實是返回一個transient HashMap.put(e, PRESENT),再跟進HashMap的put(K key, V value)方法進行查看,可以看到int hash = hash(key.hashCode());使用了set.add(key)的key做了一個哈希處理得到一個哈希碼,然后再將Entry做了一個遍歷,使用equal()方法對講原有的對象和新添加的對象進行了一個比較,如果出現了true的情況,就直接返回一個oldValue,如果在遍歷對比的過程中沒有出現ture的情況,則繼續一下的步驟modCount++,將對象總數自加,并且繼續執行addEntry()的操作,下面涉及HashMap的操作就不繼續。

          實際上HashSet的底層實現是基于HashMap,所以在此處涉及到Hash算法不展開,詳細可以見另一篇《java數據結構-HashMap

          TreeSet
          TreeSet類是實現了SortedSet接口,所以能夠對集合中的對象進行排序

                  Set iset = new TreeSet();
                  iset.add(
          new Integer(1));
                  iset.add(
          new Integer(10));
                  iset.add(
          new Integer(5));
                  iset.add(
          new Integer(8));
                  iset.add(
          "2");
                  Iterator it2 
          = iset.iterator();
                  
          while(it2.hasNext()){
                      Integer s 
          = (Integer)it2.next();
                      System.out.print(s
          +",");
                  }
                  System.out.println(
          "一共有對象:"+iset.size()+"");//打印出來的結果:1,2,5,8,10,一共有對象:5個

          當TreeSet向集合加入一個對象時,會把它插入到有序的對象序列中,TreeSet包括了兩種排序方式,自然排序和客戶化排序,在默認的情況下使用自然排序。

          自然排序
          在jdk類庫中,有部分類實現了Comparable接口,如Integer,Double等等,Comparable接口有一個compareTo()方法可以進行比較,TreeSet調用對象的compareTo()方法比較集合中對象的大小,然后進行升序排序。如Integer:

          public final class Integer extends Number implements Comparable<Integer> {

              
          public int compareTo(Integer anotherInteger) {
              
          int thisVal = this.value;
              
          int anotherVal = anotherInteger.value;
              
          return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
              }

          }

          基于Comparable的屬性,使用自然排序時,只能向TreeSet集合中加入同類型的對象,并且這些對象的類必須實現了Comparable的接口,以下我們嘗試向TreeSet集合加入兩個不同類型的對象,會發現拋出ClassCastException

          Set iset = new TreeSet();
          iset.add(
          new Integer(1));
          iset.add(
          new Integer(8));
          iset.add(
          "2");
          Exception in thread "main" java.lang.ClassCastException: java.lang.Integer

          我們再打開TreeSet的源碼進行查看

          public class TreeSet<E> extends AbstractSet<E>
              
          implements NavigableSet<E>, Cloneable, java.io.Serializable
          {
              
          private transient NavigableMap<E,Object> m;

              
          private static final Object PRESENT = new Object();

              
          public boolean add(E e) {
              
          return m.put(e, PRESENT)==null;
              }

          }

          NavigableMap為接口,實現類為TreeMap

          public class TreeMap<K,V>
              
          extends AbstractMap<K,V>
              
          implements NavigableMap<K,V>, Cloneable, java.io.Serializable
          {
              
          private final Comparator<? super K> comparator;

              
          private transient Entry<K,V> root = null;

              
          public V put(K key, V value) {
                  Entry
          <K,V> t = root;
                  
          if (t == null) {
                  
          // TBD:
                  
          // 5045147: (coll) Adding null to an empty TreeSet should
                  
          // throw NullPointerException
                  
          //
                  
          // compare(key, key); // type check
                      root = new Entry<K,V>(key, value, null);
                      size 
          = 1;
                      modCount
          ++;
                      
          return null;
                  }
                  
          int cmp;
                  Entry
          <K,V> parent;
                  
          // split comparator and comparable paths
                  Comparator<? super K> cpr = comparator;
                  
          if (cpr != null) {
                      
          do {
                          parent 
          = t;
                          cmp 
          = cpr.compare(key, t.key); //此處如果類別不相同可能拋出ClassCastException
                          if (cmp < 0)
                              t 
          = t.left;
                          
          else if (cmp > 0)
                              t 
          = t.right;
                          
          else
                              
          return t.setValue(value);
                      } 
          while (t != null);
                  }
                  
          else {
                      
          if (key == null)
                          
          throw new NullPointerException();
                      Comparable
          <? super K> k = (Comparable<? super K>) key;
                      
          do {
                          parent 
          = t;
                          cmp 
          = k.compareTo(t.key);
                          
          if (cmp < 0)
                              t 
          = t.left;
                          
          else if (cmp > 0)
                              t 
          = t.right;
                          
          else
                              
          return t.setValue(value);
                      } 
          while (t != null);
                  }
                  Entry
          <K,V> e = new Entry<K,V>(key, value, parent);
                  
          if (cmp < 0)
                      parent.left 
          = e;
                  
          else
                      parent.right 
          = e;
                  fixAfterInsertion(e);
                  size
          ++;
                  modCount
          ++;
                  
          return null;
              }

          }

          首先判斷原始集合是否存在,如果不存在則直接創建,無需比較。
          如果原始集合存在的話,先去取出Comparator對象,然后遍歷原始集合t,使用parent為臨時比較值,逐個使用compare(key, t.key)方法與添加對象key進行比較,決定元素排在集合的left或right。

          客戶端排序
          客戶端排序時因為java.util.Comparator<Type>接口提供了具體的排序方式,<Type>指定了被比較對象的類型,Comparator有個compare(Type x,Type y)的方法,用于比較兩個對象的大小。

          public class NameComparator implements Comparator<Name>{
              
              
          public int compare(Name n1,Name n2){
                  
          if(n1.getName().compareTo(n2.getName())>0return -1;
                  
          if(n1.getName().compareTo(n2.getName())<0return 1;
                  
                  
          return 0;
              }
              
              
          public static void main(String[] args) {
                  Set
          <Name> set = new TreeSet<Name>(new NameComparator());
                  
                  Name n1 
          = new Name("ray");
                  Name n2 
          = new Name("tom");
                  Name n3 
          = new Name("jame");
                  set.add(n1);
                  set.add(n2);
                  set.add(n3);
                  
                  Iterator it 
          = set.iterator();
                  
          while(it.hasNext()){
                      Name s 
          = (Name)it.next();
                      System.out.print(s.getName()
          +",");
                  }
                  System.out.println(
          "一共有對象:"+set.size()+"");
              }
          }
          //打印結果是:tom,ray,jame,一共有對象:3個

          道理與自然排序其實相同,都是通過實現Comparator接口,就不細說了,可能有些說得不對的地方,歡迎指正

          ----------------------------------------

          by 陳于喆
          QQ:34174409
          Mail: dongbule@163.com



          posted on 2011-01-06 18:07 陳于喆 閱讀(8613) 評論(0)  編輯  收藏 所屬分類: java數據結構

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 靖宇县| 达孜县| 广宁县| 崇左市| 正定县| 丰镇市| 蛟河市| 山东| 正安县| 怀安县| 共和县| 攀枝花市| 东阿县| 抚顺市| 桃园市| 南溪县| 建湖县| 大同县| 益阳市| 满城县| 岳西县| 巴南区| 邢台县| 沅陵县| 古浪县| 阿巴嘎旗| 临沭县| 南川市| 福泉市| 当雄县| 岐山县| 苍溪县| 延长县| 红河县| 兴仁县| 驻马店市| 邓州市| 阿巴嘎旗| 秦安县| 南部县| 阿拉善盟|