柚子快報(bào)激活碼778899分享:數(shù)據(jù)結(jié)構(gòu)
柚子快報(bào)激活碼778899分享:數(shù)據(jù)結(jié)構(gòu)
一、數(shù)據(jù)結(jié)構(gòu)概述
1.1 概念
在計(jì)算機(jī)科學(xué)中,數(shù)據(jù)結(jié)構(gòu)是一種數(shù)據(jù)組織、管理和存儲的格式 。它是相互之間存在一種或多種特定關(guān)系的數(shù)據(jù)元素的集合。通常情況下,精心選擇的數(shù)據(jù)結(jié)構(gòu)可以帶來更高的運(yùn)行或者存儲效率。數(shù)據(jù)結(jié)構(gòu)往往同高效的檢索算法和索引技術(shù)相關(guān)。
1.1.1 數(shù)據(jù)邏輯結(jié)構(gòu)
數(shù)據(jù)的邏輯結(jié)構(gòu)是指數(shù)據(jù)元素之間存在的邏輯關(guān)系,由數(shù)據(jù)元素的集合和定義在此集合上的關(guān)系組成。數(shù)據(jù)的邏輯結(jié)構(gòu)與數(shù)據(jù)的存儲無關(guān),獨(dú)立于計(jì)算機(jī),是從具體問題抽象出來的數(shù)學(xué)模型。
數(shù)據(jù)的邏輯結(jié)構(gòu)由兩個要素構(gòu)成,分別是:數(shù)據(jù)元素的集合和關(guān)系的集合 。
1.1.2 數(shù)據(jù)存儲結(jié)構(gòu)
數(shù)據(jù)的邏輯結(jié)構(gòu)在計(jì)算機(jī)中的存儲表示或?qū)崿F(xiàn)叫做數(shù)據(jù)的存儲結(jié)構(gòu),也叫物理結(jié)構(gòu)。數(shù)據(jù)的存儲結(jié)構(gòu)依賴于計(jì)算機(jī)。
一般來說,一種數(shù)據(jù)結(jié)構(gòu)的邏輯結(jié)構(gòu)根據(jù)需要可以表示成多種存儲結(jié)構(gòu),常用的存儲結(jié)構(gòu)有順序存儲、鏈?zhǔn)酱鎯?、索引存儲和哈希存儲等?/p>
數(shù)據(jù)的順序存儲結(jié)構(gòu)的特點(diǎn)是:借助元素在存儲器中的相對位置來表示數(shù)據(jù)元素之間的邏輯關(guān)系;非順序存儲的特點(diǎn)是:借助指示元素存儲地址的指針表示數(shù)據(jù)元素之間的邏輯關(guān)系。
1.1.3 數(shù)據(jù)的運(yùn)算
數(shù)據(jù)操作是指對數(shù)據(jù)結(jié)構(gòu)中的數(shù)據(jù)元素進(jìn)行運(yùn)算或處理。數(shù)據(jù)操作定義在數(shù)據(jù)的邏輯結(jié)構(gòu)上,每種邏輯結(jié)構(gòu)都需要一組對其數(shù)據(jù)元素進(jìn)行處理以實(shí)現(xiàn)特定功能的操作,如插入、刪除、更新等。數(shù)據(jù)操作的實(shí)現(xiàn)依賴于數(shù)據(jù)的存儲結(jié)構(gòu)。
數(shù)據(jù)的運(yùn)算包括:檢索、排序、插入、刪除、修改等。
二、常見的數(shù)據(jù)結(jié)構(gòu)
常見的數(shù)據(jù)結(jié)構(gòu)有:數(shù)組(Array)、棧(Stack)、隊(duì)列(Queue)、鏈表(Linked List)、樹(Tree)、圖(Graph)、堆(Heap)、散列表(Hash)。
2.1 數(shù)組(Array)
數(shù)組是一種線性結(jié)構(gòu),是可以在內(nèi)存中連續(xù)存儲多個元素的結(jié)構(gòu),在內(nèi)存中的分配也是連續(xù)的,數(shù)組中的元素通過數(shù)組下標(biāo)進(jìn)行訪問,數(shù)組下標(biāo)從0開始。
優(yōu)點(diǎn):訪問數(shù)據(jù)簡單。缺點(diǎn):添加和刪除數(shù)據(jù)比較耗時間,因?yàn)橐苿悠渌脑兀粩?shù)組只能存儲一種類型的數(shù)據(jù);數(shù)組的大小固定后就無法擴(kuò)容了使用場景:頻繁查詢,對存儲空間要求不大,很少增加和刪除的情況。
int[] a = {1,3,4,5,6,8,9,26,30,89};//直接創(chuàng)建并聲明容量元素的數(shù)組
int[] data = new int[100];// 創(chuàng)建一個整型int數(shù)組,大小是100個
data[0] = 1; // 向數(shù)組第一個元素賦值1;
data[1] = 2; // 向數(shù)組第二個元素賦值2;
JDK提供的順序表有:java.util.ArrayList 其底層實(shí)現(xiàn)就是數(shù)組
數(shù)組(順序表)時間復(fù)雜度分析:
查詢get(i) ,不難看出不論數(shù)據(jù)元素量N有多大,只需要一次eles[i] 就可以獲取到對應(yīng)的元素,所以時間復(fù)雜度為O(1)插入insert(int i, T t),每一次插入,都需要把i位置后面的元素移動一次,隨著元素?cái)?shù)量N的增大,移動的元素也越多,時間復(fù)雜度為O(n)刪除元素remove(int i),每一次刪除,都需要把i位置后面的元素移動一次,隨著數(shù)據(jù)量N的增大,移動的元素也越多,時間復(fù)雜度為O(n)數(shù)組長度是固定的,所以在操作的過程中涉及到了容器擴(kuò)容操作。這樣會導(dǎo)致順序表在使用過程中的時間復(fù)雜度不是線性的,在某些擴(kuò)容的結(jié)點(diǎn)處,耗時會突增,尤其是元素越多,這個問題越明顯
2.2 鏈表(Linked List)
鏈表是一種數(shù)據(jù)元素按照鏈?zhǔn)酱鎯Y(jié)構(gòu)進(jìn)行存儲的數(shù)據(jù)結(jié)構(gòu),這種存儲結(jié)構(gòu)具有在物理上非連續(xù)、非順序的特點(diǎn)。鏈表由一系列數(shù)據(jù)結(jié)點(diǎn)構(gòu)成,每個數(shù)據(jù)結(jié)點(diǎn)包括數(shù)據(jù)域和指針域兩部分。其中,指針域保存了數(shù)據(jù)結(jié)構(gòu)中下一個元素存放的地址。
鏈表結(jié)構(gòu)中數(shù)據(jù)元素的邏輯順序通過鏈表中的指針鏈接次序?qū)崿F(xiàn) 。
根據(jù)指針的指向,鏈表能形成不同的結(jié)構(gòu),例如單鏈表,雙向鏈表,循環(huán)鏈表等。
鏈表時間復(fù)雜度分析:
get(int i):每一次查詢,都需要從鏈表的頭部開始,依次向后查找,隨著數(shù)據(jù)元素N的增多,比較的元素越多,時間復(fù)雜度為O(n)insert(int i, T t):每一次插入,需要先找到i位置的前一個元素,然后完成插入操作,隨著數(shù)據(jù)元素N的增多,查找的元素越多,時間復(fù)雜度為O(n)remove(int i):每一次移除,需要先找到i位置的前一個元素,然后完成插入操作,隨著數(shù)據(jù)元素N的增多,查找的元素越多,時間復(fù)雜度為O(n)
ArrayList vs LinkedList
ArrayList
基于數(shù)組,需要連續(xù)內(nèi)存隨機(jī)訪問快(指根據(jù)下標(biāo)訪問)尾部插入、刪除性能可以,其它部分插入、刪除都會移動數(shù)據(jù),因此性能會低可以利用 cpu 緩存,局部性原理
LinkedList
基于雙向鏈表,無需連續(xù)內(nèi)存隨機(jī)訪問慢(要沿著鏈表遍歷)頭尾插入刪除性能高占用內(nèi)存多
鏈表的優(yōu)點(diǎn):?
鏈表是很常用的一種數(shù)據(jù)結(jié)構(gòu),不需要初始化容量,可以任意加減元素;?添加或者刪除元素時只需要改變前后兩個元素結(jié)點(diǎn)的指針域指向地址即可,所以添加,刪除很快;
缺點(diǎn):?
因?yàn)楹写罅康闹羔樣?,占用空間較大;?查找元素需要遍歷鏈表來查找,非常耗時。
JDK提供的鏈表有:java.util.LinkedList
適用場景:?
數(shù)據(jù)量較小,需要頻繁增加,刪除操作的場景;快慢指針:求中間值問題、單向鏈表是否有環(huán)問題、有環(huán)鏈表入口問題;循環(huán)鏈表:約瑟夫問題
2.3?棧(Stack)?
棧是一種特殊的線性表,又稱為棧。是一種基于先進(jìn)后出(FILO)的數(shù)據(jù)結(jié)構(gòu),它只能在表的固定端進(jìn)行數(shù)據(jù)結(jié)點(diǎn)的插入和刪除操作。棧按照先進(jìn)后出、后進(jìn)先出的原則來存儲數(shù)據(jù),也就是說,先插入的數(shù)據(jù)將被壓入棧底,最后插入的數(shù)據(jù)在棧頂,讀出數(shù)據(jù)時,從棧頂開始逐個讀出。
棧在匯編語言程序中,經(jīng)常用于重要數(shù)據(jù)的現(xiàn)場保護(hù)。棧中沒有數(shù)據(jù)時,稱為空棧 。
我們稱數(shù)據(jù)進(jìn)入到棧的動作為壓棧,數(shù)據(jù)從棧中出去的動作為彈棧。
JDK提供的棧有:java.util.Stack?
應(yīng)用場景:括號匹配問題;逆波蘭表達(dá)式求值問題;實(shí)現(xiàn)遞歸功能方面的場景,例如斐波那契數(shù)列。
2.4?隊(duì)列(Queue)
隊(duì)列是一種基于先進(jìn)先出(FIFO)的數(shù)據(jù)結(jié)構(gòu),是一種只能在一端進(jìn)行插入,在另一端進(jìn)行刪除操作的特殊線性表,它按照先進(jìn)先出的原則存儲數(shù)據(jù),先進(jìn)入的數(shù)據(jù),在讀取數(shù)據(jù)時先被讀取出來。
入隊(duì)列:進(jìn)行插入操作的一端稱為隊(duì)尾 出隊(duì)列:進(jìn)行刪除操作的一端稱為隊(duì)頭
JDK提供的隊(duì)列接口有:java.util.Queue
使用場景:因?yàn)殛?duì)列先進(jìn)先出的特點(diǎn),在多線程阻塞隊(duì)列管理中非常適用。
2.5?樹(Tree)
樹是典型的非線性結(jié)構(gòu),它是由n(n>0)個有限結(jié)點(diǎn)組成的一個具有層次關(guān)系的集合。在樹結(jié)構(gòu)中,有且僅有一個根結(jié)點(diǎn),該結(jié)點(diǎn)沒有前驅(qū)結(jié)點(diǎn)。在樹結(jié)構(gòu)中的其他結(jié)點(diǎn)都有且僅有一個前驅(qū)結(jié)點(diǎn)。
樹具有以下特點(diǎn):
每個結(jié)點(diǎn)有零個或多個子結(jié)點(diǎn);沒有父結(jié)點(diǎn)的結(jié)點(diǎn)為根結(jié)點(diǎn);每一個非根結(jié)點(diǎn)只有一個父結(jié)點(diǎn);除了根節(jié)點(diǎn)外,每個子節(jié)點(diǎn)可以分為多個不相交的子樹;
在日常的應(yīng)用中,我們討論和用的更多的是樹的其中一種結(jié)構(gòu),就是二叉樹、平衡樹、紅黑樹、B樹、B+樹。
應(yīng)用場景:
JDK1.8中?HashMap的底層源碼中用到了數(shù)組+鏈表+紅黑樹;磁盤文件中使用B樹做為數(shù)據(jù)組織,B樹大大提高了IO的操作效率;mysql數(shù)據(jù)庫索引結(jié)構(gòu)采用B+樹;
2.5.1?二叉樹:滿二叉樹和完全二叉樹
二叉樹是一種比較有用的折中方案,它添加,刪除元素都很快,并且在查找方面也有很多的算法優(yōu)化,所以,二叉樹既有鏈表的好處,也有數(shù)組的好處,是兩者的優(yōu)化方案,在處理大批量的動態(tài)數(shù)據(jù)方面非常有用。
二叉樹有很多擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),包括平衡二叉樹、紅黑樹、B+樹等,這些數(shù)據(jù)結(jié)構(gòu)在二叉樹的基礎(chǔ)上衍生了很多的功能,在實(shí)際應(yīng)用中廣泛用到,例如mysql的數(shù)據(jù)庫索引結(jié)構(gòu)用的就是B+樹,還有HashMap的底層源碼中用到了紅黑樹。
二叉樹是樹的特殊一種,具有如下特點(diǎn):
每個結(jié)點(diǎn)最多有兩顆子樹,結(jié)點(diǎn)的度最大為2。左子樹和右子樹是有順序的,次序不能顛倒。即使某結(jié)點(diǎn)只有一個子樹,也要區(qū)分左右子樹。
順序結(jié)構(gòu)(數(shù)組來存儲,heap里面講) 順序結(jié)構(gòu)存儲就是使用數(shù)組來存儲,一般使用數(shù)組只適合表示完全二叉樹,因?yàn)椴皇峭耆鏄鋾锌臻g的浪費(fèi)。而現(xiàn)實(shí)中使用中只有堆才會使用數(shù)組來存儲,。二叉樹順序存儲在物理上是一個數(shù)組,在邏輯上是一顆二叉樹。
鏈?zhǔn)浇Y(jié)構(gòu) 二叉樹的鏈?zhǔn)酱鎯Y(jié)構(gòu)是指,用鏈表來表示一棵二叉樹,即用鏈來指示元素的邏輯關(guān)系。 通常的方法是鏈表中每個結(jié)點(diǎn)由三個域組成,數(shù)據(jù)域和左右指針域,左右指針分別用來給出該結(jié)點(diǎn)左孩子和右孩子所在的鏈結(jié)點(diǎn)的存儲地址 。鏈?zhǔn)浇Y(jié)構(gòu)又分為二叉鏈和三叉鏈,當(dāng)前我們學(xué)習(xí)中一般都是二叉鏈,后面課程學(xué)到高階數(shù)據(jù) 結(jié)構(gòu)如紅黑樹等會用到三叉鏈。
鏈?zhǔn)浇Y(jié)構(gòu)接口如下:(包括三種遍歷方式:前序遍歷、中序遍歷、后序遍歷,以及層序遍歷)
2.6?散列表(Hash)
散列表,也叫哈希表,是根據(jù)關(guān)鍵碼和值 (key和value) 直接進(jìn)行訪問的數(shù)據(jù)結(jié)構(gòu),通過key和value來映射到集合中的一個位置,這樣就可以很快找到集合中的對應(yīng)元素。
記錄的存儲位置=f(key)
這里的對應(yīng)關(guān)系?f?成為散列函數(shù),又稱為哈希 (hash函數(shù)),而散列表就是把Key通過一個固定的算法函數(shù)既所謂的哈希函數(shù)轉(zhuǎn)換成一個整型數(shù)字,然后就將該數(shù)字對數(shù)組長度進(jìn)行取余,取余結(jié)果就當(dāng)作數(shù)組的下標(biāo),將value存儲在以該數(shù)字為下標(biāo)的數(shù)組空間里,這種存儲空間可以充分利用數(shù)組的查找優(yōu)勢來查找元素,所以查找的速度很快。
在存儲數(shù)據(jù)的過程中,如果發(fā)生沖突,可以利用鏈表在已有數(shù)據(jù)的后面插入新數(shù)據(jù)來解決沖突。這種方法被稱為“鏈地址法”。除了鏈地址法以外,還有幾種解決沖突的方法。其中,應(yīng)用較為廣泛的是“開放地址法”。
DK提供的哈希表有:java.util.HashMap
散列表應(yīng)用場景:
哈希表的應(yīng)用場景很多,當(dāng)然也有很多問題要考慮,比如哈希沖突的問題,如果處理的不好會浪費(fèi)大量的時間,導(dǎo)致應(yīng)用崩潰。解決哈希沖突問題:1?可以對數(shù)組擴(kuò)容; 2 優(yōu)化hash計(jì)算方式;
2.7?堆(Heap)
堆是一種特殊的樹形數(shù)據(jù)結(jié)構(gòu),一般討論的堆都是二叉堆。堆的特點(diǎn)是根結(jié)點(diǎn)的值是所有結(jié)點(diǎn)中最小的或者最大的,并且根結(jié)點(diǎn)的兩個子樹也是一個堆結(jié)構(gòu) 。
被用于實(shí)現(xiàn)“優(yōu)先隊(duì)列”(priority queues)。優(yōu)先隊(duì)列是一種數(shù)據(jù)結(jié)構(gòu),可以自由添加數(shù)據(jù),但取出數(shù)據(jù)時要從最小值開始按順序取出。在堆的樹形結(jié)構(gòu)中,各個頂點(diǎn)被稱為“結(jié)點(diǎn)”(node),數(shù)據(jù)就存儲在這些結(jié)點(diǎn)中。堆有下列特點(diǎn):
每個節(jié)點(diǎn)最多有兩個子節(jié)點(diǎn)排列順序必須從上到下,同一行從左到右堆中某個節(jié)點(diǎn)的值總是不大于或不小于其父節(jié)點(diǎn)的值;存放數(shù)據(jù)時,一般會把新數(shù)據(jù)放在最下面一行靠左的位置。如果最下面一行沒有多余空間時,就再往下另起一行,并把數(shù)據(jù)添加到這一行的最左端。
堆的性質(zhì):
堆是一個完全二叉樹堆中某個結(jié)點(diǎn)的值總是不大于或不小于其父結(jié)點(diǎn)的值;除了樹的最后一層結(jié)點(diǎn)不需要是滿的,其它的每一層從左到右都是滿的,如果最后一層結(jié)點(diǎn)不是滿的,那么要求左滿右不滿;它通常用數(shù)組來實(shí)現(xiàn);
將根結(jié)點(diǎn)最大的堆叫做最大堆或大根堆,根結(jié)點(diǎn)最小的堆叫做最小堆或小根堆。常見的堆有二叉堆、
斐波那契堆等。
一棵深度為k的有n個結(jié)點(diǎn)的二叉樹,對樹中的結(jié)點(diǎn)按從上至下、從左到右的順序進(jìn)行編號,
如果編號為i(1≤i≤n)的結(jié)點(diǎn)與滿二叉樹中編號為i的結(jié)點(diǎn)在二叉樹中的位置相同,則這棵二叉樹
稱為完全二叉樹。
一棵深度為k且有2^k?1個結(jié)點(diǎn)的二叉樹稱為滿二叉樹。也就是說除了葉子節(jié)點(diǎn)都有2個子節(jié)點(diǎn),且
所有的葉子節(jié)點(diǎn)都在同一層。
堆應(yīng)用場景:因?yàn)槎延行虻奶攸c(diǎn),一般用來做數(shù)組中的排序,稱為堆排序。
2.8?圖(Graph)
圖是另一種非線性數(shù)據(jù)結(jié)構(gòu)。圖的數(shù)據(jù)結(jié)構(gòu)包含一個有限的集合作為結(jié)點(diǎn)集合,以及一個無序?qū)Γ▽?yīng)無向圖)或有序?qū)Γ▽?yīng)有向圖)的集合作為邊的集合。如果兩個結(jié)點(diǎn)之間存在一條邊,那么就表示這兩個結(jié)點(diǎn)具有相鄰關(guān)系 。
無向圖:
有向圖:
圖的搜索:
深度優(yōu)先搜索:指的是在搜索時,如果遇到一個結(jié)點(diǎn)既有子結(jié)點(diǎn),又有兄弟結(jié)點(diǎn),那么先找子結(jié)點(diǎn),然后找兄弟結(jié)點(diǎn)。廣度優(yōu)先搜索:指的是在搜索時,如果遇到一個結(jié)點(diǎn)既有子結(jié)點(diǎn),又有兄弟結(jié)點(diǎn),那么先找兄弟結(jié)點(diǎn),然后找子結(jié)點(diǎn)。
圖的應(yīng)用場景:
道路暢通工程最短路徑
柚子快報(bào)激活碼778899分享:數(shù)據(jù)結(jié)構(gòu)
推薦閱讀
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。