電腦程式的思維邏輯 (55) - 容器類總結

来源:http://www.cnblogs.com/swiftma/archive/2016/12/02/6124015.html
-Advertisement-
Play Games

本節從三個角度簡要總結之前介紹的各種容器類:用法和特點,數據結構和演算法,設計思維和模式。 ...


38節54節,我們介紹了多種容器類,本節進行簡要總結,我們主要從三個角度進行總結:

  1. 用法和特點
  2. 數據結構和演算法
  3. 設計思維和模式 

用法和特點

我們在52節展示過一張圖,其中包含了容器類主要的介面和類,我們還是用這個圖總結一下:

容器類有兩個根介面,分別是Collection和Map,Collection表示單個元素的集合,Map表示鍵值對的集合。

Collection表示的數據集合有基本的增、刪、查、遍歷等方法,但沒有定義元素間的順序或位置,也沒有規定是否有重覆元素。

List是Collection的子介面,表示有順序或位置的數據集合,增加了根據索引位置進行操作的方法。它有兩個主要的實現類,ArrayListLinkedList,ArrayList基於數組實現,LinkedList基於鏈表實現,ArrayList的隨機訪問效率很高,但從中間插入和刪除元素需要移動元素,效率比較低,LinkedList則正好相反,隨機訪問效率比較低,但增刪元素只需要調整鄰近節點的鏈接。

Set也是Collection的子介面,它沒有增加新的方法,但保證不含重覆元素。它有兩個主要的實現類,HashSetTreeSet,HashSet基於哈希表實現,要求鍵重寫hashCode方法,效率更高,但元素間沒有順序,TreeSet基於排序二叉樹實現,元素按比較有序,元素需要實現Comparable介面,或者創建TreeSet時提供一個Comparator對象。HashSet還有一個子類LinkedHashSet可以按插入有序。還有一個針對枚舉類型的實現類EnumSet,它基於位向量實現,效率很高。

Queue是Collection的子介面,表示先進先出的隊列,在尾部添加,從頭部查看或刪除。Deque是Queue的子介面,表示更為通用的雙端隊列,有明確的在頭或尾進行查看、添加和刪除的方法。普通隊列有兩個主要的實現類,LinkedListArrayDeque,LinkedList基於鏈表實現,ArrayDeque基於迴圈數組實現,一般而言,如果只需要Deque介面,ArrayDeque的效率更高一些。

Deque還有一個特殊的實現類PriorityQueue,它表示優先順序隊列,內部是用實現的,堆除了用於實現優先順序隊列,還可以高效方便的解決很多其他問題,比如求前K個最大的元素、求中值等。

Map介面表示鍵值對集合,經常根據鍵進行操作,它有兩個主要的實現類,HashMapTreeMap。HashMap基於哈希表實現,要求鍵重寫hashCode方法,操作效率很高,但元素沒有順序。TreeMap基於排序二叉樹實現,要求鍵實現Comparable介面,或提供一個Comparator對象,操作效率稍低,但可以按鍵有序。

HashMap還有一個子類LinkedHashMap,它可以按插入或訪問有序。之所以能有序,是因為每個元素還加入到了一個雙向鏈表中。如果鍵本來就是有序的,使用LinkedHashMap而非TreeMap可以提高效率。按訪問有序的特點可以方便的用於實現LRU緩存。

如果鍵為枚舉類型,可以使用專門的實現類EnumMap,它使用效率更高的數組實現。

需要說明的是,我們介紹的各種容器類都不是線程安全的,也就是說,如果多個線程同時讀寫同一個容器對象,是不安全的。如果需要線程安全,可以使用Collections提供的synchronizedXXX方法對容器對象進行同步,或者使用線程安全的專門容器類。

此外,容器類提供的迭代器都有一個特點,都會在迭代中間進行結構性變化檢測,如果容器發生了結構性變化,就會拋出ConcurrentModificationException,所以不能在迭代中間直接調用容器類提供的add/remove方法,如需添加和刪除,應調用迭代器的相關方法。

在解決一個特定問題時,經常需要綜合使用多種容器類。比如要統計一本書中出現次數最多的前10個單詞,可以先使用HashMap統計每個單詞出現的次數,再使用47節介紹的TopK類用PriorityQueue求前十個10單詞,或者使用Collections提供的sort方法。

在之前各節介紹的例子中,為簡單起見,容器中的元素類型往往是簡單的,但需要說明的是,它們也可以是複雜的自定義類型,也可以是容器類型。比如在一個新聞應用中,表示當天的前十大新聞可以用一個List表示,形如List<News>,而為了表示每個分類的前十大新聞,可以用一個Map表示,鍵為分類Category,值為List<News>,形如Map<Category, List<News>>,而表示每天的每個分類的前十大新聞,可以在Map中使用Map,鍵為日期,值也是一個Map,形如Map<Date, Map<Category, List<News>>。

數據結構和演算法

在容器類中,我們看到瞭如下數據結構的應用:

  • 動態數組:ArrayList內部就是動態數組,HashMap內部的鏈表數組也是動態擴展的,ArrayDeque和PriorityQueue內部也都是動態擴展的數組。
  • 鏈表:LinkedList是用雙向鏈表實現的,HashMap中映射到同一個鏈表數組的鍵值對是通過單向鏈錶鏈接起來的,LinkedHashMap中每個元素還加入到了一個雙向鏈表中以維護插入或訪問順序。
  • 哈希表:HashMap是用哈希表實現的,HashSet, LinkedHashSet和LinkedHashMap基於HashMap,內部當然也是哈希表。
  • 排序二叉樹:TreeMap是用紅黑樹(基於排序二叉樹)實現的,TreeSet內部使用TreeMap,當然也是紅黑樹,紅黑樹能保持元素的順序且綜合性能很高。
  • :PriorityQueue是用堆實現的,堆邏輯上是樹,物理上是動態數組,堆可以高效地解決一些其他數據結構難以解決的問題。
  • 迴圈數組:ArrayDeque是用迴圈數組實現的,通過對頭尾變數的維護,實現了高效的隊列操作。
  • 位向量:EnumSet是用位向量實現的,對於只有兩種狀態,且需要進行集合運算的數據,使用位向量進行表示、位運算進行處理,精簡且高效。 

每種數據結構中往往包含一定的演算法策略,這種策略往往是一種折中,比如:

  • 動態擴展演算法:動態數組的擴展策略,一般是指數級擴展的,是在兩方面進行平衡,一方面是希望減少記憶體消耗,另一方面希望減少記憶體分配、移動和拷貝的開銷。
  • 哈希演算法:哈希表中鍵映射到鏈表數組索引的演算法,演算法要快,同時要儘量隨機和均勻。
  • 排序二叉樹的平衡演算法:排序二叉樹的平衡非常重要,紅黑樹是一種平衡演算法,AVL樹是另一種,平衡演算法一方面要保證儘量平衡,另一方面要儘量減少綜合開銷。

Collections實現了一些通用演算法,比如二分查找、排序、翻轉列表順序、隨機化重排、迴圈移位等,在實現大部分演算法時,Collections也都根據容器大小和是否實現了RandomAccess介面採用了不同的實現方式。

設計思維和模式

在容器類中,我們也看到了Java的多種語言機制和設計思維的運用:

  • 封裝:封裝就是提供簡單介面,並隱藏實現細節,這是程式設計的最重要思維。在容器類中,很多類、方法和變數都是私有的,比如迭代器方法,基本都是通過私有內部類或匿名內部類實現的。
  • 繼承和多態:繼承可以復用代碼,便於按父類統一處理,但我們也說過,繼承是一把雙刃劍。在容器類中,Collection是父介面,List/Set/Queue繼承自Collection,通過Collection介面可以統一處理多種類型的集合對象。容器類定義了很多抽象容器類,具體類通過繼承它們以復用代碼,每個抽象容器類都有詳細的文檔說明,描述其實現機制,以及子類應該如何重寫方法。容器類的設計展示了介面繼承、類繼承、以及抽象類的恰當應用。
  • 組合:一般而言,組合應該優先於繼承,我們看到HashSet通過組合的方式使用HashMap,TreeSet通過組合使用TreeMap,適配器和裝飾器模式也都是通過組合實現的。
  • 介面面向介面編程是一種重要的思維,可降低代碼間的耦合,提高代碼復用程度,在容器類方法中,接受的參數和返回值往往都是介面,Collections提供的通用演算法,操作的也都是介面對象,我們平時在使用容器類時,一般也只在創建對象時使用具體類,而其他地方都使用介面。
  • 設計模式:我們在容器類中看到了迭代器、工廠方法、適配器、裝飾器等多種設計模式的應用。

小結

本節我們從用法和特點、數據結構和演算法、以及設計思維和模式三個角度簡要總結了之前介紹的各種容器類。到此為止,關於容器類我們就介紹完了。

到目前為止,我們還沒有接觸過文件處理,而我們在日常的電腦操作中,接觸最多的就是各種文件了,讓我們從下一節開始,一起探討文件操作。

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

更多相關原創文章

(14) 類的組合

(18) 為什麼說繼承是把雙刃劍

(19) 介面的本質

(20) 為什麼要有抽象類?

(21) 內部類的本質

(38)  剖析ArrayList

(39)  剖析LinkedList

(40)  剖析HashMap

(41)  剖析HashSet

(42)  排序二叉樹

(43)  剖析TreeMap

(44)  剖析TreeSet

(45)  神奇的堆

(46)  剖析PriorityQueue

(47)  堆和PriorityQueue的應用

(48)  剖析ArrayDeque

(49)  剖析LinkedHashMap

(50)  剖析EnumMap

(51)  剖析EnumSet

(52)  抽象容器類

(53) 剖析Collections - 演算法

(54) 剖析Collections - 設計模式

 

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

未完待續,查看最新文章,敬請關註微信公眾號“老馬說編程”(掃描下方二維碼),從入門到高級,深入淺出,老馬和你一起探索Java編程及電腦技術的本質。用心原創,保留所有版權。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在目前的軟體項目中,都會較多的使用到對文檔的操作,用於記錄和統計相關業務信息。由於系統自身提供了對文檔的相關操作,所以在一定程度上極大的簡化了軟體使用者的工作量。 在.NET項目中如果用戶提出了相關文檔操作的需求,開發者較多的會使用到微軟自行提供的插件,在一定程度上簡化了開發人員的工作量,但是同時也 ...
  • 1.設置gridview裡面的屬性中ShowFooter="True",就是把gridview的頁腳顯示出來 this.gvData.OptionsView.ShowFooter = true; 2.設置要彙總的列,例如彙總"ReceiveMoney"金額列 3.給gridView添加CustomS ...
  • 假設有如下代碼所示的多線程: 這個新建的線程t在執行完Test()方法後會自動銷毀嗎?還是需要寫代碼手動銷毀呢? 下麵就多線程的非主線程銷毀機製做個總結: 1).t結束就自動銷毀了 2).設置線程屬性IsBackground=true 將線程t作為後臺線程,隨著主線程結束而一起結束,不管這個線程有沒 ...
  • 最近一直在研究Paypal的支付平臺,因為本人之前沒有接觸過介面這一塊,新來一家公司比較不清楚流程就要求開發兩個支付平臺一個是支付寶(這邊就不再這篇文章裡面贅述了),但還是花了2-3天的時間通過自己研究和借鑒別人的文章以及強大的Paypal官方技術文檔搞清楚了真正的原理和開發過程。(如有不同見解或者 ...
  • 上個月月底,VS2017RC版發佈了,一個很大的特點就是將原來的xProj文件又改回了csproj了。 這樣一改,其實很多新的問題也暴露出來了,最嚴重的問題就是Net版本相容性。 原來的Net體系大致是NetFramework,Net Core這樣的,雖然也有Net Standard 這樣的概念,但 ...
  • 本隨筆續接:.NET 實現並行的幾種方式(三) 八、await、async - 非同步方法的秘密武器 1) 使用async修飾符 和 await運算符 輕易實現非同步方法 前三篇隨筆已經介紹了多種方式、利用多線程、充分利用多核心CPU以提高運行效率。但是以前的方式在WebAPI和GUI系統上、 使用起來 ...
  • 用法一、this代表當前實例,用this.來調用當前實例的成員方法,變數,屬性,欄位等 ...
  • 官方資料: "https://github.com/dotnet/core" "https://docs.microsoft.com/en us/aspnet/core" "https://docs.microsoft.com/en us/ef/core" 相關文章: "ASP.NET 5 RC1 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...