0)個(gè)有限節(jié)點(diǎn)組成的一個(gè)具有層次關(guān)系的集合;6、堆;7、圖;8、哈希表。" />

bt天堂在线www,男人的天堂av网站,国内精品伊人久久久久av影院,欧美精品中文字幕亚洲专区,大人和孩做爰av

400-609-4309

Java數(shù)據(jù)結(jié)構(gòu)有哪些-java數(shù)據(jù)結(jié)構(gòu)是什么

Java數(shù)據(jù)結(jié)構(gòu)有哪些-java數(shù)據(jù)結(jié)構(gòu)是什么

摘要

Java數(shù)據(jù)結(jié)構(gòu),簡(jiǎn)單說(shuō)就是Java里用來(lái)“整理和管理數(shù)據(jù)”的“工具箱”——它決定了數(shù)據(jù)怎么存、怎么取、怎么改,直接影響代碼的效率和穩(wěn)定性。不管你是剛學(xué)Java的新手,還是想跳槽的程序員,搞懂它都是繞不開(kāi)的坎:寫項(xiàng)目時(shí)選對(duì)數(shù)據(jù)結(jié)構(gòu),代碼能快好幾倍;面試時(shí)被問(wèn)“ArrayList和LinkedList的區(qū)別”,答不上來(lái)可能就錯(cuò)失offer。今天這篇文章,咱們從“數(shù)據(jù)結(jié)構(gòu)到底是啥”講起,把Java里常用的結(jié)構(gòu)一個(gè)個(gè)拆明白,附代碼示例和避坑指南,保證你看完就能用。

一、Java數(shù)據(jù)結(jié)構(gòu)到底是什么?先搞懂“為什么要學(xué)它”

你可能會(huì)說(shuō):“我寫代碼就是定義變量、調(diào)API,數(shù)據(jù)結(jié)構(gòu)聽(tīng)起來(lái)好抽象,有必要學(xué)嗎?”

舉個(gè)例子:你要存100個(gè)學(xué)生的成績(jī),用數(shù)組存和用鏈表存,后續(xù)想查第50個(gè)學(xué)生的成績(jī),前者可能0.001秒就搞定,后者可能要遍歷半天才找到——這就是數(shù)據(jù)結(jié)構(gòu)的影響。數(shù)據(jù)結(jié)構(gòu)本質(zhì)是“數(shù)據(jù)的組織方式”,就像圖書館的書架:按編號(hào)排列(數(shù)組)、按類別分層(樹(shù))、隨便堆在筐里(集合),不同的“擺法”,找書的效率天差地別。

對(duì)Java程序員來(lái)說(shuō),數(shù)據(jù)結(jié)構(gòu)更是基礎(chǔ)中的基礎(chǔ):

寫項(xiàng)目時(shí):比如電商系統(tǒng)的購(gòu)物車,用HashMap存商品ID和數(shù)量,查商品時(shí)直接“按ID找”,比遍歷數(shù)組快10倍;

面試時(shí):“HashMap底層原理”“紅黑樹(shù)怎么旋轉(zhuǎn)”幾乎是必考題,不懂基本過(guò)不了技術(shù)面;

解決問(wèn)題時(shí):遇到“Top K問(wèn)題”(比如找銷量前10的商品),用堆結(jié)構(gòu)能輕松搞定,用數(shù)組硬算可能超時(shí)。

所以別再覺(jué)得它“沒(méi)用”——你寫的每一行代碼,背后都離不開(kāi)數(shù)據(jù)結(jié)構(gòu)的影子。

二、Java里常用的數(shù)據(jù)結(jié)構(gòu)有哪些?從基礎(chǔ)到進(jìn)階,一個(gè)個(gè)說(shuō)透

Java的數(shù)據(jù)結(jié)構(gòu)主要分兩大類:基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)(數(shù)組、棧、隊(duì)列等)和集合框架(Java Collections Framework,簡(jiǎn)稱JCF,比如List、Set、Map)。咱們從最常用的開(kāi)始聊,每個(gè)都講清楚“是什么、怎么用、什么時(shí)候用”。

2.1 最“樸素”的結(jié)構(gòu):數(shù)組(Array)——簡(jiǎn)單但夠用

定義:數(shù)組是Java里最基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu),就是“一組連續(xù)的內(nèi)存空間”,存相同類型的數(shù)據(jù),通過(guò)下標(biāo)(索引)訪問(wèn)。

類比:就像你家的儲(chǔ)物柜,每個(gè)格子有編號(hào)(0、1、2...),格子里放的東西類型一樣(比如全是衣服),想拿第3個(gè)格子的衣服,直接按編號(hào)找就行。

特點(diǎn)

優(yōu)點(diǎn):查詢快(通過(guò)下標(biāo)直接訪問(wèn),時(shí)間復(fù)雜度O(1))、簡(jiǎn)單直觀;

缺點(diǎn):長(zhǎng)度固定(初始化時(shí)必須指定大小,想擴(kuò)容得新建數(shù)組復(fù)制元素)、增刪慢(中間位置增刪元素,后面的元素都要移動(dòng))。

適用場(chǎng)景:數(shù)據(jù)量固定、需要頻繁查詢、很少增刪的場(chǎng)景,比如存一周的溫度數(shù)據(jù)、學(xué)生的學(xué)號(hào)列表。

代碼示例

// 定義一個(gè)長(zhǎng)度為5的int數(shù)組,存5個(gè)學(xué)生的成績(jī)

int[] scores = new int[5];

scores[0] = 90; // 存數(shù)據(jù)(下標(biāo)從0開(kāi)始)

scores[1] = 85;

System.out.println(scores[0]); // 查數(shù)據(jù):直接通過(guò)下標(biāo),輸出90

// 數(shù)組擴(kuò)容(手動(dòng)實(shí)現(xiàn),實(shí)際開(kāi)發(fā)很少用,因?yàn)橛蠥rrayList)

int[] newScores = new int[10]; // 新建更大的數(shù)組

for (int i = 0; i < scores.length; i++) {

newScores[i] = scores[i]; // 復(fù)制舊數(shù)據(jù)

}

scores = newScores; // 指向新數(shù)組

2.2 最常用的“動(dòng)態(tài)數(shù)組”:ArrayList——數(shù)組的“升級(jí)版”

定義:ArrayList是Java集合框架里的“動(dòng)態(tài)數(shù)組”,底層還是數(shù)組,但解決了“長(zhǎng)度固定”的問(wèn)題——它會(huì)自動(dòng)擴(kuò)容(默認(rèn)初始容量10,滿了就按1.5倍擴(kuò)容)。

類比:就像帶“自動(dòng)擴(kuò)容功能”的儲(chǔ)物柜,你放滿了,它會(huì)自動(dòng)加一排新格子,不用你手動(dòng)搬東西。

特點(diǎn)

優(yōu)點(diǎn):查詢快(和數(shù)組一樣,O(1))、自動(dòng)擴(kuò)容、支持動(dòng)態(tài)增刪(比數(shù)組方便);

缺點(diǎn):中間/頭部增刪慢(需要移動(dòng)元素,時(shí)間復(fù)雜度O(n))、擴(kuò)容時(shí)可能浪費(fèi)內(nèi)存(比如實(shí)際只存11個(gè)元素,擴(kuò)容后容量是15,空4個(gè)格子)。

適用場(chǎng)景:需要頻繁查詢、增刪主要在尾部的場(chǎng)景,比如存用戶的瀏覽歷史(一般只在末尾加新記錄,查最近瀏覽直接取最后幾個(gè))。

代碼示例

import java.util.ArrayList;

public class Test {

public static void main(String[] args) {

// 創(chuàng)建ArrayList,存String類型(不用指定長(zhǎng)度)

ArrayList history = new ArrayList<>();

// 增:尾部添加元素(快)

history.add("首頁(yè)");

history.add("商品列表");

history.add("購(gòu)物車");

// 查:通過(guò)下標(biāo)(快)

System.out.println(history.get(1)); // 輸出“商品列表”

// 刪:中間元素(慢,因?yàn)楹竺娴脑匾耙疲?/p>

history.remove(1); // 刪除“商品列表”,此時(shí)列表變成["首頁(yè)","購(gòu)物車"]

// 遍歷

for (String s : history) {

System.out.println(s);

}

}

}

2.3 增刪“靈活選手”:LinkedList——鏈表的“代表”

定義:LinkedList底層是“雙向鏈表”,每個(gè)元素(節(jié)點(diǎn))存數(shù)據(jù)+前后節(jié)點(diǎn)的地址,就像火車車廂,每個(gè)車廂連著前一個(gè)和后一個(gè)。

類比:春運(yùn)時(shí)排隊(duì)買票,你想插到中間,不用所有人都挪位置,只要前一個(gè)人和后一個(gè)人“認(rèn)識(shí)”你就行;你走了,前一個(gè)人和后一個(gè)人再重新“認(rèn)識(shí)”——這就是鏈表的增刪邏輯。

特點(diǎn)

優(yōu)點(diǎn):中間/頭部增刪快(只需要改前后節(jié)點(diǎn)的地址,時(shí)間復(fù)雜度O(1))、不需要擴(kuò)容(節(jié)點(diǎn)動(dòng)態(tài)創(chuàng)建);

缺點(diǎn):查詢慢(必須從頭遍歷,時(shí)間復(fù)雜度O(n))、占內(nèi)存多(每個(gè)節(jié)點(diǎn)要存前后地址)。

適用場(chǎng)景:需要頻繁在中間增刪的場(chǎng)景,比如實(shí)現(xiàn)“鏈表式隊(duì)列”“ undo/redo操作”(比如Word的撤銷功能,每次操作加到鏈表頭部,撤銷時(shí)直接取頭部元素)。

代碼示例

import java.util.LinkedList;

public class Test {

public static void main(String[] args) {

LinkedList undoList = new LinkedList<>();

// 頭部添加(快,鏈表強(qiáng)項(xiàng))

undoList.addFirst("輸入文字");

undoList.addFirst("插入圖片");

undoList.addFirst("設(shè)置格式");

// 查第一個(gè)元素(快,因?yàn)橛蓄^節(jié)點(diǎn)指針)

System.out.println(undoList.getFirst()); // 輸出“設(shè)置格式”

// 刪第一個(gè)元素(撤銷操作,快)

undoList.removeFirst(); // 此時(shí)列表變成["插入圖片","輸入文字"]

}

}

小提醒:別用fori循環(huán)遍歷LinkedList!因?yàn)槊看蝕et(i)都要從頭數(shù),遍歷n個(gè)元素要O(n2)時(shí)間,用foreach循環(huán)(迭代器)才是O(n)。

2.4 去重“神器”:Set——不允許重復(fù)元素的集合

Set和List的最大區(qū)別是不允許重復(fù)元素(底層通過(guò)equals()和hashCode()判斷是否重復(fù)),常用的有HashSet和TreeSet。

2.4.1 HashSet:無(wú)序去重,性能之王

底層:哈希表(數(shù)組+鏈表/紅黑樹(shù)),存元素時(shí)先算hashCode找位置,相同hashCode再用equals比較。

特點(diǎn):無(wú)序(存和取的順序可能不一樣)、去重快(O(1))、允許存null(但只能存一個(gè))。

適用場(chǎng)景:需要快速去重、不關(guān)心順序的場(chǎng)景,比如存用戶ID(避免重復(fù)登錄)。

代碼示例

import java.util.HashSet;

public class Test {

public static void main(String[] args) {

HashSet userIds = new HashSet<>();

userIds.add("u1001");

userIds.add("u1002");

userIds.add("u1001"); // 重復(fù)元素,添加失敗

System.out.println(userIds.size()); // 輸出2(只存了2個(gè)不重復(fù)的ID)

}

}

2.4.2 TreeSet:有序去重,自帶排序

底層:紅黑樹(shù)(一種平衡二叉樹(shù)),會(huì)按元素的自然順序(比如數(shù)字從小到大、字符串按字典序)排序。

特點(diǎn):有序(按規(guī)則排序)、去重、查詢/增刪O(log n)(比HashSet慢一點(diǎn))。

適用場(chǎng)景:需要去重且排序的場(chǎng)景,比如存學(xué)生成績(jī)并按分?jǐn)?shù)從高到低排列。

代碼示例

import java.util.TreeSet;

public class Test {

public static void main(String[] args) {

TreeSet scores = new TreeSet<>();

scores.add(85);

scores.add(90);

scores.add(75);

scores.add(90); // 重復(fù),添加失敗

System.out.println(scores); // 輸出[75, 85, 90](自動(dòng)排序)

}

}

2.5 鍵值對(duì)“王者”:Map——按“key”快速找“value”

Map是“鍵值對(duì)”集合,就像字典:“單詞”(key)對(duì)應(yīng)“解釋”(value),通過(guò)key能快速找到value。Java里最常用的是HashMap和TreeMap。

2.5.1 HashMap:最常用,查詢快到飛起

底層:哈希表(數(shù)組+鏈表/紅黑樹(shù),JDK1.8后優(yōu)化),key不重復(fù)(重復(fù)會(huì)覆蓋value),無(wú)序。

特點(diǎn):查詢/增刪O(1)(理想情況)、無(wú)序、允許key為null(只能一個(gè))。

適用場(chǎng)景:需要通過(guò)key快速查value的場(chǎng)景,比如存用戶信息(key是用戶ID,value是用戶對(duì)象)、統(tǒng)計(jì)單詞出現(xiàn)次數(shù)(key是單詞,value是次數(shù))。

代碼示例

import java.util.HashMap;

public class Test {

public static void main(String[] args) {

// 存用戶信息:key=用戶ID,value=用戶名

HashMap userMap = new HashMap<>();

userMap.put("u1001", "張三");

userMap.put("u1002", "李四");

// 查:通過(guò)key找value(快)

System.out.println(userMap.get("u1001")); // 輸出“張三”

// 遍歷key-value

for (String key : userMap.keySet()) {

System.out.println(key + ":" + userMap.get(key));

}

}

}

2.5.2 TreeMap:按key排序的Map

底層:紅黑樹(shù),key會(huì)按自然順序排序,和TreeSet類似。

特點(diǎn):key有序、查詢/增刪O(log n)、key不能為null。

適用場(chǎng)景:需要按key排序的場(chǎng)景,比如存“月份-銷售額”,并按月份順序展示。

2.6 特殊場(chǎng)景“工具人”:棧(Stack)和隊(duì)列(Queue)

棧(Stack):后進(jìn)先出(LIFO)

定義:就像疊盤子,最后放的盤子最先拿。Java里常用Deque(雙端隊(duì)列)的push()(入棧)、pop()(出棧)方法實(shí)現(xiàn),比古老的Stack類更推薦。

適用場(chǎng)景:括號(hào)匹配、瀏覽器后退、表達(dá)式求值(比如后綴表達(dá)式)。

代碼示例

import java.util.Deque;

import java.util.LinkedList;

public class Test {

public static void main(String[] args) {

Deque stack = new LinkedList<>();

stack.push("首頁(yè)"); // 入棧

stack.push("商品頁(yè)");

stack.push("詳情頁(yè)");

System.out.println(stack.pop()); // 出棧,輸出“詳情頁(yè)”(最后進(jìn)的先出)

}

}

隊(duì)列(Queue):先進(jìn)先出(FIFO)

定義:就像排隊(duì)買票,先到的先買。Java里常用LinkedList實(shí)現(xiàn)Queue接口,add()(入隊(duì))、poll()(出隊(duì))。

適用場(chǎng)景:任務(wù)調(diào)度(比如線程池的任務(wù)隊(duì)列)、消息隊(duì)列(比如訂單消息按順序處理)。

代碼示例

import java.util.LinkedList;

import java.util.Queue;

public class Test {

public static void main(String[] args) {

Queue queue = new LinkedList<>();

queue.add("訂單1"); // 入隊(duì)

queue.add("訂單2");

queue.add("訂單3");

System.out.println(queue.poll()); // 出隊(duì),輸出“訂單1”(先進(jìn)先出)

}

}

三、怎么選對(duì)數(shù)據(jù)結(jié)構(gòu)?3個(gè)“懶人技巧”,新手也能秒懂

學(xué)了這么多,你可能會(huì)暈:“這么多結(jié)構(gòu),我寫代碼時(shí)到底用哪個(gè)?”記住3個(gè)原則,不用死記硬背:

技巧1:看“操作類型”——查詢多還是增刪多?

頻繁查詢(比如按位置取元素):選ArrayList(數(shù)組)、HashMap(按key查);

頻繁增刪(尤其是中間位置):選LinkedList(鏈表);

兩端增刪(棧/隊(duì)列操作):用Deque(LinkedList實(shí)現(xiàn))。

技巧2:看“是否需要去重”——元素能不能重復(fù)?

需要去重:用Set(HashSet/TreeSet);

允許重復(fù):用List(ArrayList/LinkedList)。

技巧3:看“是否需要排序”——順序重要嗎?

需要排序:用TreeSet(按元素排)、TreeMap(按key排);

不需要排序:用HashSet、HashMap(性能更好)。

舉個(gè)例子:存班級(jí)學(xué)生的名字,可能重復(fù)(允許重名),需要頻繁按學(xué)號(hào)(位置)查名字——選ArrayList;存班級(jí)學(xué)生的學(xué)號(hào)(不重復(fù)),需要按學(xué)號(hào)從小到大排——選TreeSet。

四、避坑指南:這些“坑”我踩過(guò),你別再犯

ArrayList初始化時(shí)指定容量:默認(rèn)初始容量10,存滿了會(huì)1.5倍擴(kuò)容(復(fù)制數(shù)組),如果知道大概數(shù)據(jù)量,直接指定容量(比如new ArrayList<>(1000)),能減少擴(kuò)容次數(shù),提升性能。

別用HashMap存多線程數(shù)據(jù):HashMap線程不安全,多線程下可能出現(xiàn)死循環(huán),用ConcurrentHashMap替代。

LinkedList別用get(i)遍歷:前面說(shuō)過(guò),fori循環(huán)遍歷LinkedList效率極低,用foreach或迭代器。

TreeSet/TreeMap的key要實(shí)現(xiàn)Comparable:如果存自定義對(duì)象,需要讓對(duì)象類實(shí)現(xiàn)Comparable接口,否則會(huì)報(bào)錯(cuò)(因?yàn)椴恢涝趺磁判颍?

最后:數(shù)據(jù)結(jié)構(gòu)不難,用起來(lái)才是王道

很多人覺(jué)得數(shù)據(jù)結(jié)構(gòu)“難”,其實(shí)是因?yàn)橹豢磿粚?shí)踐。你不用背下所有底層原理(比如紅黑樹(shù)的旋轉(zhuǎn)細(xì)節(jié)),但至少要知道“ArrayList和LinkedList怎么選”“HashMap為什么快”。

下次寫代碼時(shí),別急著上手,先想清楚:我要存什么數(shù)據(jù)?怎么存查起來(lái)最快?怎么刪改最方便?把今天講的結(jié)構(gòu)套進(jìn)去,多試幾次,自然就懂了。

畢竟,編程的本質(zhì)是“解決問(wèn)題”,而數(shù)據(jù)結(jié)構(gòu),就是你手里最趁手的“工具”。

12 12 分享:

相關(guān)課程

發(fā)表評(píng)論

登錄后才能評(píng)論,請(qǐng)登錄后發(fā)表評(píng)論...
提交評(píng)論

最新文章