1. 前言
程序員的一天是怎樣開啟的?
清晨打開儲存著各種結(jié)構(gòu)數(shù)據(jù)的冰箱,從雞蛋集 “盒” 中提取了一枚數(shù)據(jù)扔進煎鍋,從西蘭花樹形結(jié)構(gòu)上查找最新鮮的一支跟雞蛋一起煎熟,從袋裝切片面包數(shù)組中取出兩片,用圖形結(jié)構(gòu)的花生醬數(shù)據(jù)涂抹均勻,撕開新買的養(yǎng)樂多隊列 get (0),想要清爽一點可以再從腌黃瓜的棧里 pop () 兩片昨天剛放進去的鮮嫩數(shù)據(jù)。
程序員的世界離不開數(shù)據(jù)結(jié)構(gòu),畢竟我們的主要工作內(nèi)容之一就是用邏輯和算法來處理數(shù)據(jù),而合理地使用數(shù)據(jù)結(jié)構(gòu)就像冰箱里使用恰當?shù)娜萜鱽戆b食物一樣重要。
2. 為什么要學習數(shù)據(jù)結(jié)構(gòu)
數(shù)據(jù)結(jié)構(gòu)既是各類考試的必考部分,也是各類公司面試題里的常客,但是如果僅僅是為了以上兩點來學習數(shù)據(jù)結(jié)構(gòu),那就未免顧此失彼了。其實學習數(shù)據(jù)結(jié)構(gòu)對我們的工作和學習有著很大的幫助,我大概總結(jié)出來我個人感受比較深的幾個點跟大家分享:
- 幫助我們有更多更好的手段來使用數(shù)據(jù),特別是了解各種數(shù)據(jù)結(jié)構(gòu)的原理能夠幫助我們在實際開發(fā)工作中遇到大數(shù)據(jù)、高性能、大并發(fā)等業(yè)務場景時選擇正確的處理方式;
- 充分發(fā)揮計算機的性能,使我們的代碼更加高效,在代碼優(yōu)化的過程中可以更明確的在時間維度和空間維度之間做出平衡或選擇;
- 學習的過程本身又是提升我們思考問題能力的過程,可以提升我們對算法的了解和認識,拓寬設(shè)計思路,同時提升對全局問題思考的格局和高度;
3. 數(shù)據(jù)結(jié)構(gòu)的定義
百度詞條對數(shù)據(jù)結(jié)構(gòu)(data structure)的定義是:
帶有結(jié)構(gòu)特性的數(shù)據(jù)元素的集合,它研究的是數(shù)據(jù)的邏輯結(jié)構(gòu)和數(shù)據(jù)的物理結(jié)構(gòu)以及它們之間的相互關(guān)系,并對這種結(jié)構(gòu)定義相適應的運算,設(shè)計出相應的算法,并確保經(jīng)過這些運算以后所得到的新結(jié)構(gòu)仍保持原來的結(jié)構(gòu)類型。
通俗地講,就是數(shù)據(jù)元素是以何種形式在計算機上存儲,又是以何種形式被程序員使用,它們之間的關(guān)系以及我們可以使用的算法。
4. 數(shù)據(jù)結(jié)構(gòu)的分類
數(shù)據(jù)結(jié)構(gòu)的分類一般有兩種維度,一種是根據(jù)數(shù)據(jù)結(jié)構(gòu)的原理從它們的邏輯結(jié)構(gòu)來區(qū)分,一種是從數(shù)據(jù)結(jié)構(gòu)存儲時的物理結(jié)構(gòu)來區(qū)分。
邏輯結(jié)構(gòu),是針對數(shù)據(jù)之間的相互關(guān)系而言的,通??梢苑譃榫€性結(jié)構(gòu)和非線性結(jié)構(gòu)。線性結(jié)構(gòu)中的數(shù)據(jù)元素之間存在著一對一的關(guān)系,非線性結(jié)構(gòu)中的數(shù)據(jù)元素之間存在著一對多或者多對多的關(guān)系,而數(shù)組中的數(shù)據(jù)元素相互之間沒有任何關(guān)系,他們只是同一類型數(shù)據(jù)的集合。
物理結(jié)構(gòu),是針對數(shù)據(jù)在存儲器中的存儲方法而言的,通??梢苑譃?strong>順序存儲和鏈式存儲。順序存儲的數(shù)據(jù)是在一段連續(xù)的空間中,靠相對位置來表示元素之間的相互關(guān)系,像在一個小教室上課的同班同學靠前后座關(guān)系就能建立聯(lián)系;鏈式存儲的數(shù)據(jù)內(nèi)存地址不一定是連續(xù)的,每一個節(jié)點上都有一個指針存儲域,靠指針來建立元素之間的相互關(guān)系,像幾個班級的同學同時上公選課時分散在一個大教室里,同一個班級的同學之間需要靠學號來建立聯(lián)系。
5. Java 中常用的數(shù)據(jù)結(jié)構(gòu)
Java 中常用的數(shù)據(jù)結(jié)構(gòu)都在 java.util 包下,都是對 Collection 和 Map 兩個頂級接口的實現(xiàn)類。這里要注意不是 java.util.Collections,Collections 是一個對集合中元素進行查詢、排序等操作的工具類,我們下面還會提到。

6. 常用的算法
算法是我們處理數(shù)據(jù)結(jié)構(gòu)的具體實現(xiàn)步驟,一個好的算法評價標準是效率足夠高、存儲足夠低。我們可以簡單地分成增、刪、改、查,外加排序五類,排序又可以分為插入排序,交換排序、選擇排序、歸并排序、分配排序等,而具體實現(xiàn)根據(jù)結(jié)構(gòu)和算法的不同,執(zhí)行的效率也會不同。
好在我們有很多現(xiàn)成的工具可以用可以使我們不必從零開始設(shè)計一個健壯、高效、可讀性好的優(yōu)秀的算法。這時候我們可以祭出一個利器 ——java.util.Collections,它實現(xiàn)了對于數(shù)據(jù)結(jié)構(gòu)的各種靜態(tài)多態(tài)方法來對集合實現(xiàn)搜索、排序、線程安全化等等操作。我們可以從源代碼或者官方 API 中了解它都提供了哪些方法。
7. 小結(jié)
本節(jié)我們簡要介紹了數(shù)據(jù)結(jié)構(gòu)的定義、分類及其算法。大家可以把數(shù)據(jù)結(jié)構(gòu)理解成我們封裝數(shù)據(jù)的容器,而算法就像是我們對容器中的物品進行查看、添加、使用和整理的思路及方法。本節(jié)的內(nèi)容更多的是需要大家了解和熟悉,后面我們會結(jié)合 Java 源碼來介紹各類數(shù)據(jù)結(jié)構(gòu)的特點和用法。