本文主講介紹幾種常用的數據結構,數據結構是一種容器的一個分支,容器時用來裝東西的,那麼數據結構就是專門用來存儲數據的容器。首先我們從數組來給大家漸漸引入數據結構,容器的概念。那麼數組是什麼呢,數組是一個對象,準確的說我們將對象進行分類,具有特定功能的對象就被成為數據結構或者容器,集合等,數組就是其中之一。有一個人說過程序就是算法與數據結構,這句話大體上能夠描述程序。
我們從數組的特性來慢慢延伸到集合。如果面試官要你介紹一下數組該怎麼說呢,它的容量是固定的,其中每個元素對應一個唯一的下標,通過下標我們可以找到相應的元素,那麼這種通過K找到V的結構我們稱為表對吧。
首先從數組的容量來看,它的容量是在一開始被創建就固定了的,如int[] i={1,2,3};或者int[] is=new int[8];那我們如何對數組進行擴容呢,看如下代碼
擴容用乘法,縮減用除法,使用原有數組長度作為一個新的標準量來參照擴大或縮小的倍數,那為什麼不手動輸入一個數字來定義數組大小呢,那樣就把代碼寫死了,實際上應該是原數組長度*n。我們除了會對容量進行操作外,其次就是最重要的增刪了,改是非常簡單的,直接通過下標取出元素然後賦值即可。那麼我該如何向數組中刪除一個元素呢
這是我剛剛學習java時寫的一小段代碼,它用於刪除數組指定下標的元素,邏輯就是將要刪除的下標置換到數組尾部然後縮減數組長度,添加也是同樣的方法,總之是非常的麻煩,那麼對數組這種結構可以歸納為數組是一種被創建時長度固定,難增刪的數據結構,但是它由於有下標作為索引所以能夠快速定位到指定下標的元素,同時java.util.Arrays是JDK提供的對數組操作的工具類,它用於幫助我們更好地使用數組,包括
//Arrays.sort(a, c);//Arrays.binarySearch(a, key) //Arrays.deepEquals(a1, a2) //Arrays.parallelPrefix(array, op); //Arrays.stream(array)
這幾種方法,第一個排序,第二個使用二分法搜索,第三個判斷兩個數組是否每個元素都一致,第四第五都是JDK8提供的,用於函數式編程。其他還有fill填充等,可以自己挨個去看看。
它還有一個很有意思的方法叫做Arrays.asList(),該方法要求傳入一個數組變量然後能夠將數組轉為List,那麼List是什麼呢?
List是一種非常常用的數據結構,叫做鍊表。為了避免數組插入和刪除對資源的線性開銷,就是數組長度越長添加元素耗費的資源就越多,使用不連續存儲的鍊表就能夠解決這個問題。鍊表的思想是每個元素首位相連,因為叫做鍊表所以它其實還是一種KV結構,第一個元素的V作為第二個元素的K,第二個元素的V作為第三個元素的K,最後一個元素的V為null。如果不明白的話可以想像一下電影人體蜈蚣,這種結構的好處就是我們對其增刪只需要斷開前一個元素的V和後一個元素的K即可,就像插件一樣,是可插拔的。List是一個接口,它有兩個子類,ArrayList和LinkedList,看名字就可以看得出一種是基於數組實現另一個是基於鍊表實現的。LinkedList相比ArrayList而言有更高效的插入和刪除執行速度, LinkedList才是真正意義上的鍊表。鍊表的特點就是增刪快,但是搜索指定元素消耗的資源也是呈現線性增長的。
除了數組和鍊表之外還有很多很多種延伸出的結構被用作不同的應用場景,如果你理解數組和鍊表那麼遇到新的數據結構也會容易上手,也可以自定義一個自己需要的容器。Set是一種自帶去重的容器,它和List一樣同屬Collection的子類,特點就是不會出現重複元素。有兩個常用子類hashSet和linkedHashSet,hashSet的內部是一個hashMap,特點是取出元素的順序不一定與存入順序一致,它沒有一個專門用於記錄順序的索引, linkedHashSet是一個有序的set,它有專門用於記錄順序的索引。
下一個數據結構就是Map,map是一種特殊的結構,它內部儲存的是鍵值對,與List都是同為表,區別就是map的K是可以被我們使用的,它將K,V封裝為一個整體Entry,這裡的Entry作為一個元素,相當於List中的一個元素,然後Entry中還有兩個元素K和V。Map接口有一個上面提到過的子類HashMap,只要看帶有Hash前綴的容器就說明,它的索引是由哈希算法也叫散列算法計算得出的,它是一種摘要算法也就是我們常用的md5,sha256的原型,這種算法計算得出的索引是唯一的,那麼map的特點就是Entry中的K唯一,V可以重複。它也提供了很多自己獨有的API,所以map的應用面積較廣。本次代碼較少,接下來將從代碼層面深入講解每個容器的實現。