數據結構-線性表

數據結構-線性表

線性表結構:線性表:數組、鏈表、棧、隊列前端

1.數組:連續的內存空間。java


  1.1  查找:隨機查找的時間複雜度爲O(1),注意,只是隨機查找(用下標的方式)。排序後的二分查找時間複雜度O(logn)數據庫

    中間插入和刪除:須要搬移元素位置,時間複雜度爲O(n)編程

    開頭和結尾插入和刪除:O(1)後端

    插入優化技巧:若是條件容許,插入到第K個位置時,能夠把第K個位置的元素移動到最後,減小數據搬運數組

    刪除優化技巧:若是條件容許,能夠幾個刪除一塊兒後,再搬移元素。(相似JVM的垃圾回收,標記清除法)

  1.2 JAVA中的ArrayList封裝了數組,相比數組優點:動態擴容瀏覽器

      (1)擴容時,新建一個大的數組,而後數據拷貝到這個新的數組。緩存

    (2)擴容大小:原來容量的1.5倍數據結構

    (3)數組和ArrayList的選擇:通常使用ArrayList,可是對於底層框架的開發,須要把性能作到極致,能夠選擇數組。併發

  1.3 二維數組能夠表示矩陣

    針對稀疏矩陣的表示:若是直接表示會浪費存儲空間。能夠採用三項式來表示。

    A(0,1)表示矩陣的行數

    A(0,2)表示矩陣的列數

    A(0,3)表示矩陣的非零項的總數

    A(i,j,value) 表示非零的項。i從1開始,第i行第j列的值爲value

  1.4 數組和多項式

    P(x) = a0 + a1x + a2*x^2 + a3*x^3 + ... + + an*x^n

    好比 2x^5 + 3x^4 + 5x^2 + 4x + 1

    方法一:使用n+2長度的一維數組存儲,第一個元素是最大的指數n,其他元素按n遞減存儲多項式的係數。若是沒有的存儲0

      A = {5,2,3,0,5,4,1} ,其中這裏沒有x^3的係數,因此第四項爲0

      缺點:若是有x^100,那麼素組的長度爲100+1

    方法二:只存儲多項式非零項。第一個元素爲多項式非零項的個數。

      A = {5,2,5,3,4,5,2,4,1,1,0}

      缺點:計算時可能會更復雜些

2.鏈表:不要求內存空間連續

  2.1  插入和刪除:適合大量的操做 O(1);查詢: O(n)

 

  2.2  JAVA中的LinkedList爲雙向鏈表,有next也有previous

    LinkedList能夠實現棧、隊列以及雙端隊列等數據結構

    LinkedList能夠實現LRU緩存機制

  2.3  單向鏈表:指針和數據(第一個接節點是鏈表頭指針,最後一個指針設置爲null)

    循環鏈表:最後一個指針指向鏈表頭部,從任何一個節點入手,能夠遍歷全部其餘節點

    環形鏈表:一般應用於內存工做區與輸入/到處緩衝區

    雙向鏈表:優點是能夠輕鬆找到先後節點

    雙向循環鏈表

 

  2.4 鏈表和多項式:和數組的方法同樣,只是鏈表實現的好處是適合多項式內容變更

 

  2.5 環形鏈表能夠實現稀疏矩陣:優勢是矩陣變動時不須要大量移動數據

 

3.跳錶(跳躍表):經過多級索引使得鏈表可以實現二分查找,加速鏈表的隨機查詢效率,似於二分查找。

    查詢(不支持隨機查詢):O(logn)

    空間複雜度:O(n)

    場景: Redis使用了跳錶。

    HBase MemStore的也使用的跳錶。爲何呢?

      HBase 屬於 LSM Tree 結構的數據庫,LSM Tree 結構的數據庫有個特色,實時寫入的數據先寫入到內存

      內存達到閾值往磁盤 flush 的時候,會生成相似於 StoreFile 的有序文件,而跳錶剛好就是自然有序的

      因此在 flush 的時候效率很高,並且跳錶查找、插入、刪除性能都很高,這應該是 HBase MemStore 內部存儲數據使用跳錶的緣由之一。

      HBase 使用的是 java.util.concurrent 下的 ConcurrentSkipListMap()。

 

4.棧:先入後出,當作桶。(操做受限的數組或鏈表結構)

  4.1 添加、刪除複雜度都是O(1);查詢: O(n)

  4.2 能夠數組實現(順序棧)和鏈表實現(鏈式棧)(數組不利於大小動態變化,可是優勢是編程簡單)只須要一個top指針指向棧頂元素。

  4.3 應用:瀏覽器前進後退

        函數調用

            表達式取值

 

5.隊列Queue:先入先出,通俗理解:排隊。(操做受限的數組或鏈表結構)

 

  5.1 添加、刪除複雜度都是O(1);查詢: O(n)

    在高級語言中,通常不用純粹的棧和隊列,java能夠用雙端隊列替代。

  5.2 能夠數組(順序隊列)和鏈表(鏈式隊列)實現。

      線程池中的各類策略:

    鏈表實現:無界隊列,不合適響應時間敏感的。

    數組實現:有界隊列,適合響應時間敏感的。

 

    環形隊列與鏈式隊列的選擇:若是能夠肯定最大的大小,那麼選擇環形隊列。若是不能肯定,那麼選擇鏈式隊列。

 

  5.3 須要兩個指針front和rear分別指向前端和後端。

 

  5.4 應用:做業調度、磁盤的緩衝區。

 

  5.5 雙端隊列Deque:兩邊均可以進出。兩邊都須要front和rear指針。

  5.6 循環隊列 : MapReduce中Shuffle時使用了。

            注意:環形隊列是使用數組實現的,解決順序隊列的數據搬運問題。

  5.7 優先隊列Priority Queue

    插入和刪除:O(1)

    取出操做:O(logn),按照優先級

    底層實現能夠多樣:heap、bst、treap

 

    java中實現:PriorityQueue

  5.8 阻塞隊列和併發隊列(CAS)

 

6.哈希表Hash table(散列表):經過哈希函數(散列函數)映射值。

  6.1 模型:Hash函數獲得數組下標 -> 數組(鏈表做爲數組的元素)

    插入和刪除:O(1)

    查詢:O(1)

    說明:可能後面鏈表查詢的複雜度不爲1,可是通常hashCode一致的比較少,

          因此鏈表的元素個數其實頗有限,能夠認爲就是O(1)。

  6.2 哈希函數

    (1)除後取餘數法

    (2)平方取中

  6.3 java 7中的HashMap是數組和鏈表的結合體。JAVA 8中是數組 + 紅黑樹實現。

    (1)對象的HashCode是用來在散列存儲結構中肯定對象的存儲地址的。

    (2)若是兩個對象的HashCode相同,即在數組中的地址相同。而數組的元素是鏈表。這兩個對象會放在同一鏈表上。

    (3)如何肯定是同一個對象? 經過equals方法。

    (4)HashMap默認的加載因子是0.75,默認最大容量是16。

       所以能夠得出HashMap的默認實際容量是:0.75*16=12,到了12就會擴容。

                     擴容大小:擴容原來的一倍。

                還有經常使用的 HashMap HashSet。

 

7. 應用:算術表達式的表示方法

  中序法(操做數1-運算符-操做數2): 2*3 + 4*5

  中序表達法符合人的習慣,不過計算機處理不方便

  前序法(運算符-操做數1-操做數2): +*23*45

  經常使用的計算機處理方式

    後序法(操做數1-操做數2-運算符): 23*45*+

  經常使用的計算機處理方式(比前序經常使用)

  7.1 利用堆棧實現表達式運算:最簡單的是後續表達式求值-只須要一個棧。

 

  7.2 可使用二叉樹的方法

 

  7.3 中序轉前序/後序

    2*3 + 4*5

  (1)括號法: 先括號括起來((2*3) + (4*5))

    中序轉前序

      用括號內的運算符替代左括號,近者優先:+*23)*45))

      去掉全部右括號:+*23*45

    中序轉後序

      用括號內的運算符替代右括號,近者優先:((23* (45*+

      去掉全部左括號:23*45*+

  (2)堆棧法

  7.4 前序或後序轉中序

  (1)括號法

  (2)堆棧法

相關文章
相關標籤/搜索