數據結構
數據結構:
數據結構_棧:先進后出
- 入口和出口在同一側
數據結構_隊列:先進先出
- 入口和出口在集合的兩側
數據結構_數組:
- 查詢快:數組的地址是連續的,我們通過數組的首地址可以找到數組,通過數組的索引可以快速的查找某一個元素。
- 增刪慢:數組的長度是固定的,我們想要增加/刪除一個元素,必須創建一個新數組,把原數組的數據復制過來
例: int[] arr = new int[]{1,2,3,4};
要把數組索引是3的元素刪除
- 必須創建一個新的數組,長度是原數組的長度-1
- 把原數組的其它元素復制到新數組中
- 在新數組的地址賦值給變量arr
- 原數組會在內存中被銷毀(垃回收收)
數據結構_鏈表:
- 查詢慢:鏈表中地址不是連續的,每次查詢元素,都必須從頭開始查詢。
- 增刪快:鏈結構,增加/刪除一個元素,對鏈的整體結構沒有影響,所以增刪快
鏈表中的每一個元素也稱之為一個節點
一個節點包含了一個數據源(存儲數組),兩指針域(存儲地址)
- 單向鏈:鏈中只有一條鏈,不能保證元素的順序(存儲元素和取出元素的順序可能不一致)
- 雙向鏈:鏈中有兩鏈,有一條鏈是專門記錄元素的順序,是一個有序的集合
二叉樹:分支不能超過兩
- 排序樹/查找樹:在二叉樹的基礎上,元素是有大小順序的(左子樹小,右子樹大)
- 平衡樹:左孩子和右孩子相等
- 不平衡樹:左孩子和右孩子不相等
紅黑樹:
特點:趨近於平衡樹,查詢的速度非常的快,查詢葉子節點最大次數和最小次數不能超過2倍
約束:
- 節點可以是紅色的或者是黑色的
- 根節點是黑色的
- 葉子節點(空節點)是黑色的
- 每個紅色的節點的子節點都是黑色的
- 任何一個節點到其每一個葉子節點的所有路徑上黑色節點數相等
List接口
java.util.list接口 extends Collection接口
List接口的特點:
- 有序的集合,存儲元素和取出元素的順序是一致的(存儲123 取出123)
- 有索引,包含了一些帶索引的方法
- 允許存儲重復的元素
List接口中帶索引的方法(特有):
public void add(int index,E element):將指定的元素,添加到該集合中的指定位置上。 public E get(int index):返回集合中指定位置的元素。 public E remove(int index):移除列表中指定位置的元素,返回的是被移除的元素。 public E set(int index,E element):用指定元素替換集合中指定位置的元素,返回值的更新前的元素。
注意:
操作索引的時候,一定要防止索引越界異常
- IndexOutOfBoundsException:索引越界異常,集合會報
- ArrayIndexOutOfBoundsException:數組索引越界異常
- StringIndexOutOfBoundsException:字符串索引越界異常
//創建一個List集合對象,多態 List<String> list = new ArrayList<>(); { //public void add(int index,E element):將指定的元素,添加到該集合中的指定位置上。 //在索引2和索引3之間添加一個cainiao list.add(3,"cainiao");//{a,b,c,d}-->{a,b,c,cainiao,d} //移除元素 String removeE = list.remove(2) //替換元素 String setE = list.set(4,"A"); }
List的子類
- ArrayList集合
java.util.ArrayList集合數據存儲的結構是數組結構。元素增刪慢,查找快,由於日常開發中使用最多的功能為查詢數據、遍歷數據,所以ArrayList是最常用的集合。
- LinkedList集合
java.util.LinkedList集合數據存儲的結構是鏈結構。方便元素添加,刪除的集合。
java.util.LinkedList集合 implements List接口
ArrayList集合的特點:
- 底層是一個鏈的結構:查詢慢,增刪快
- 里邊包含了大量操作首尾元素的方法
注意:
使用ArrayList集合特有的方法,不能使用多態
- public void addFirst(E e):將指定元素插入此列表的開頭
- public void addLast(E e):將指定元素添加到此列表的結尾
- public void addpush(E e):將元素推如此列表所表示的推棧
- public E getFirst():返回此列表的第一個元素。
- public E getLast():返回此列表的最后一個元素。
- public E removeFirst():移除並返回此列表的第一個元素。
- public E removeLast():移除並返回此列表的最后一個元素。
- public E pop():從此列表所表示的推棧處彈出一個元素。相當於removeFirst
- public boolean isEmpty():如果列表不包含元素,則返回true
Vector集合
Vector 類可以實現可增長的對象數組。
與新collection不同,Vector是同步的。
Set接口
java.util.Set接口 extends Collection接口
Set接口的特點:
- 不允許存儲重復的元素
- 沒有索引,沒有帶索引的方法,也不能使用普通的for循環遍歷
java.util.HashSet集合 implements Set接口
HashSet特點:
- 不允許存儲重復的元素
- 沒有索引,沒有帶索引的方法,也不能使用普通的for循環遍歷
- 是一個無序的集合,存儲元素和取出元素的順序有可能不一致
- 底層是一個哈希表結構(查詢的速度非常快)
Set<Integer> set = new HashSet<>(); //使用add方法往集合中添加元素 set.add(1); set.add(3); set.add(2); set.add(1); //使用迭代器遍歷Set集合 Iterator<Integer> it = set.iterator(); while(it.hasNext(){ Iterator n = it.next(); System.out.println(n);//1,2,3 無序且不重復 }
HashSet集合存儲數據的結構(哈希表)
哈希值:是一個十進制的整數,由系統隨機給出(就是對象的地址值,是一個邏輯地址,是模擬出來得到的地址,不是數據實際存儲的物理地址)
在Object類有一個方法,可以獲取對象的哈希值
int hashCode() 返回該對象的哈希碼值。
HashCode方法的源碼:
public native int hashCode(); native:代表該方法調用的是本地操作系的的方法
哈希表
哈希表:hashSet集合存儲數據的結構
jdk1.8版本之前:哈希表 = 數組+鏈表
jdk1.8版本之后:
- 哈希表 = 數組+鏈表;
- 哈希表 = 數組+紅黑樹(提高查詢的速度)
哈希表的特點:速度快
存儲數據到集合中,先計算元素的哈希值
- abc:96354 在數組的存儲位置
- 重地——通話:1179395 兩元素不同,但是哈希值相同 哈希沖突
數組結構:把元素進行了分組(相同哈希值的元素是一組)
鏈表/紅黑樹結構:把相同哈希值的元素連到一起(如何鏈表的長度超過了8位,那么就會把鏈轉換位紅黑樹(提高查詢的速度))
Set集合存儲元素不重復的原理
Set集合存儲元素不重復的元素的前提:
前提:存儲的元素必須重寫hashCode方法和equals方法
//創建HashSet集合對象 HashSet<String> set = new HashSet<>();//哈希表:數組+鏈表/紅黑樹 String s1 = new String("abc"); String s2 = new String("abc"); set.add(s1); set.add(s2); set.add("重地"); set.add("通話"); set.add("abc"); System.out.println(set);/[重地,通話,abc]
原因:
Set集合在調用add方法的時候,add方法會調用元素hashCode方法和equals方法,判斷元素是否重復
HashSet存儲自定義類型元素
Set集合報錯元素原因:
存儲的元素(String,Integer,...Student,Person...),必須重寫hashCode方法和equals方法
LinkedHashSet集合
java.util.LinkedHashSet集合 extends HashSet集合
LinkedHashSet集合特點:
底層是一個哈希表(數組+鏈表/紅黑樹+鏈表:多了一條鏈(記錄元素的存儲順序),保存元素有序
HashSet<String> set = new HashSet<>();//[]無序,不允許重復 LinkedHashSet<String> set = new LinkedHashSet<>();[]//有序,不允許重復
可變參數
可變參數:是JDK1.5 之后出現的新特性
使用前提:
- 當方法的參數列表數據類型已經確定,但是參數的個數不確定,就可以使用可變參數。
使用格式:定義方法時使用
- 修飾符 返回值類型 方法名(數據類型...變量名){}
可變參數的原理:
- 可變參數底層就是一個數組,根據傳遞參數個數不同,會創建不同長度的數組,來存儲這些參數
- 傳遞的參數個數,可以是0個 (不傳遞),1,2...多個
可變參數的注意事項:
- 一個方法的參數列表,只能有一個可變參數
- 如果方法的參數有多個,那么可變參數必須寫在參數列表的末尾
public static void method(String b, double c ,int d ,int...a){} //可變參數的特殊(終極)寫法 public static void method(Object...obj){} Collections集合工具類的方法 java.util.Collections是集合工具類,用來對集合進行操作。部分方法如下: public static <T> void sort(List<T> List ,Comparator<? super T>):將集合中元素按照指定規則排序。 Comparator和Comparable的區別 Comparable:自己(this)和別人(參數)比較,自己需要實現Comparable接口,重寫比較的規則compareTo方法 Comparator:相當於找一個第三方的裁判,比較兩 Comparator的排序規則: o1-o2:升序
Map集合
Collection接口: 定義了單列集合規范 Collection<E>
- 每次存儲一個元素 單個元素
Map接口:定義了雙列集合的規范 Map<K,V>
- 每次存儲一對元素
java.util.Map<K,V>集合
Map集合的特點:
- Map集合是一個雙列集合,一個元素包含兩值(一個key,一個value)
- Map集合中的元素,key和value的數據類型可以相同,也可以不同
- Map集合中的元素,key是不允許重復的,value是可以重復的
- Map集合中的元素,key和value是一一對應的
java.util.HashMap<K,V>集合 implements Map<K,V>接口
HashMap集合的特點:
1.HashMap集合底層是哈希值:查詢的速度特別的快
- JDK.8之前:數組+單向鏈表
- JDK.8之后:數組+單向鏈表/紅黑樹(鏈表的長度超過8):提高查詢的速度
2.HashMap集合是一個無序的集合,存儲元素和取出元素的順序有可能不一致
java.util.LinkedHashMap<k,v>集合 extends HashMap<K,V>集合
LinkedHashMap的特點:
- LinkedHashMap集合底層是哈希表+鏈表(保證迭代的順序)
- LinkedHashMap集合是一個有序的集合,存儲元素和取出元素的順序是一致的
Map接口中的常用方法
public V put (K key,V value):把指定的鍵與指定的值添加到Map集合中。
返回值:v
- 存儲鍵值對的時候,key不重復,返回值V是null
- 存儲鍵值對的時候,key重復,會使用新的value替換map中重復的value,返回被替換的value值
public V remove(Object key):把指定的值 所對應的鍵值對元素 在Map集合中刪除,返回被刪除元素的值。
返回值:V
- key存在,v返回被刪除的值
- key不存在,v返回null
public V get(Object key)根據指定的鍵,在Map集合中獲取對應的值。
返回值:
- key存在,返回對應的value值
- key不存在,返回null
boolean containsKey(Object key) 判斷集合中是否包含指定的鍵
- 包含返回true,不包含返回false
Map集合的第一種遍歷方式:通過鍵找值的方式
Map集合中的方法:
- Set<K> keySet() 返回此映射中包含的鍵的 Set 視圖。
實現步驟:
- 使用Map集合中的方法keySet(),把Map集合所有的key取出來,存儲到一個Set集合中。
- 遍歷Set集合,獲取Map集合中的每一個Key
- 通過Map集合中的方法get(key),通過key找到value
Entry鍵值對對象
Map.Entry<K,V>:在Map接口中有一個內部接口Entry
作用:當Map集合一創建,那么就會在Map集合中創建一個Entry對象,用來記錄鍵與值(鍵值對對象,鍵與值的映射關系)
Map集合遍歷的第二種方式:使用Entry對象遍歷
Set<Map.Entry<K,V> entrySet() 返回此映射中包含的鍵的 Set 視圖。
實現步驟:
- Set<Map.Entry<K,V>> entrySet(): 把Map集合內部的多個Entry對象取出來存儲到一個Set集合中
- 遍歷Set集合:獲取Set集合中的每一個Enter對象
- 獲取Entry對象中的方法:getKey()獲取key,getValue() 獲取value
HashMap存儲自定義類型鍵值
key:Person類型
- Person類型必須重寫hashCode方法和equals方法,以保證key唯一
value:String類型
- 可以重復
java.util.linkedHashMap<K,V> extends HashMap<K,V>
Map 接口的哈希表和鏈表列表實現,具有可預知的迭代順序。
底層原理:
- 哈希表+鏈表(記錄元素的順序)
Hashtable集合
java.util.Hashtable<K,V>集合 implements Map<k,V>接口
- Hashtable:底層也是一個哈希表,是一個線程安全的集合,是單線程集合,速度慢
- HashMap:底層是一個哈希表,是一個線程不安全的集合,是多線程的集合,速度快
- HashMap集合(之前學的所有集合):可以存儲null值,null鍵
- Hashtable集合:不能存儲null值,null鍵
- Hashtable集合和Vector集合一樣,在jdk1.2版本之后被更先進的集合(HashMap,ArrayList)取代了
- Hashtable的子類properties依然活躍在歷舞台
- Properties集合是一個唯一和I/O流相結合的集合
練習:
- 計算一個字符串中每一個字符出現的次數
分析:
1.使用Scanner獲取用戶輸入的字符串
2.創建Map集合,key是字符串中的字符,value是字符的個數
3.遍歷字符串,獲取每一個字符
4.使用獲取到的字符,去Map集合判斷key是否存在
- key存在:
通過字符(key),獲取value(字符個數) value++ put(key,value)把新的value存儲到Map集合中
- Key不存在:
put(key,1)
5.遍歷Map集合,輸出結果
public class CaiNiao{ public static void main(String[] args){ //1.使用Scanner獲取用戶輸入的字符串 Scanner sc = new Scanner(System.in); System.out.println("請輸入一個字符串:"); String str = sc.next(); //2.創建Map集合,key是字符串中的字符,value是字符的個數 HashMap<Character.Integer> map = new HashMap<>(); //3.遍歷字符串,獲取每一個字符 for(char c : str.toCharArray()){ //4.使用獲取到的字符,去Map集合判斷key是否存在 if(map.containsKey(c)){ //key存在 Integer value = map.get(c); value++; map.put(c,value); }else{ //key不存在 map.put(c,1); } } //5.遍歷Map集合,輸出結果 for(Character key : map.keySet(){ Integer value = map.get(key); System.out.println(key+"="+value); } } }
JDK9對集合添加的優化
JDK9的新特性:
- list接口,Set接口,Map接口:里邊增加了一個靜態的方法of,可以給集合一次性添加多個元素
- static <E> List<E> of (E... elements)
使用前提:
- 當集合中存儲的元素的個數已經確定了,不在改變時使用
注意:
- of方法只適用於list接口,set接口,Map接口,不適用於接口的實現類
- 2of方法的返回值是一個不能改變的集合,集合不能再使用add,put方法添加元素,會拋出異常
- 3Set接口和Map接口在調用of方法的時候,不能有重復的元素,否則會拋出異常
Debug追蹤
Debug調試程序:
- 可以讓代碼逐行執行,查看代碼執行的過程,調試程序中出現的bug
使用方式:
- 在行號的右邊,鼠標左鍵單擊,添加斷點(每個方法的第一行,哪里有bug添加到哪里)
- 右鍵,選擇Debug執行程序
- 程序就會停留在添加的第一個斷點處
執行程序:
- f8:逐行執行程序
- f7:進入到方法中
- shift + f8:跳出方法
- f9:跳到下一個斷點,如果沒有下一個斷點,那么就結束程序
- ctrl + f2:退出debug模式,停止程序
斗地主綜合案例:有序版本(雙列)
- 1.准備牌
- 2.洗牌
- 3.發牌
- 4.排序
- 5.看牌

import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class CaiNiao{ public static void main(String[] args){ //1.准備牌 //創建一個Map集合,存儲牌的索引和組裝好的牌 HashMap<Integer,String> poker = new HashMap<>(); //創建一個List集合,存儲花色和牌索引 ArrayList<Integer> pokerIndex = new ArrayList<>(); //定義兩個數組,一個數組存儲牌的花色,一個數組存儲牌的序號 String[] colors = {"?","?","?","??"}; String[] numbers = {"2","A","K","Q","J","10","9","8","7","6","5","4","3"}; //先把大王和小王存儲到集合中 //定義一個牌的索引 int index = 0; poker.put(index,"大王"); pokerIndex.add(index); index++; poker.put(index,"小王"); pokerIndex.add(index); index++; //循環嵌套遍歷兩個數組,組裝52張牌 for(String numbers:numbers){ for (String color : colors){ poker.put(index.color+number); pokerIndex.add(index); index++; } } // System.out.println(poker); // System.out.println(pokerIndex); /* 2.洗牌 使用集合的工具類Collections中的方法 static void shuffle(List<?> list) 使用默認的隨機源對指定列表進行置換。 */ Collections.shuffle(poker); //System.out.println(poker); /* 3.發牌 */ //定義4 個集合,存儲玩家的牌和底牌 ArrayList<String> player01 = new ArrayList<>(); ArrayList<String> player02 = new ArrayList<>(); ArrayList<String> player03 = new ArrayList<>(); ArrayList<String> dipai = new ArrayList<>(); /* 遍歷poker集合,獲取每一張牌 使用poker集合的索引%3給3個玩家輪流發牌 剩余3張牌給底牌 注意: 先判斷底牌(i>51),否則牌就發沒了 */ for(int i = 0;i<poker.size();i++){ //獲取每一張牌 String p = poker.get(i); //輪流發牌 if(i>=51){ //給底牌發牌 diPai.add(p); }else if (i%3==0){ //給玩家1發牌 player01.add(p); }else if (i%3==1){ //給玩家2發牌 player02.add(p); }else if(i%3==2){ //給玩家3發牌 player03.add(p); } } /* 4.排序 使用Collectio中的方法sort(List) 默認是升序排序 */ Collection.sort(player01); Collection.sort(player02); Collection.sort(player03); Collection.sort(dipai); //5.看牌 lookpoker("劉德華:",poker,player01); lookpoker("周潤發:",poker,player02); lookpoker("周星馳:",poker,player03); lookpoker("底牌 :",poker,dipai); } /* 定義一個看牌方法,提高代碼的復用性 參數: String name:玩家名稱 HashMap<Integer,String> poker:存儲牌的poker集合 ArrayList<Integer> List:存儲玩家和底牌的list集合 查表法: 遍歷玩家或者底牌集合,獲取牌的索引 使用牌的索引,去Map集合中,找到對應的牌 */ public static void lookpoker(String name ,HashMap<Integer,String> poker,ArrayList<Integer> list){ //輸出玩家名稱,不換行 System.out.println(name + ";"); //遍歷玩家或者底牌集合,獲取牌的索引 for(Integer key : list){ //使用牌的索引,去Map集合中,找到對應的牌 String value = poker.get(key); System.out.println(value+""); } System.out.println();//打印完每一個玩家的牌,換行 } }
