數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)

什么是數(shù)據(jù)結(jié)構(gòu)翰蠢?

數(shù)據(jù)結(jié)構(gòu)就是計(jì)算機(jī)存儲(chǔ)和組織數(shù)據(jù)的方式

  • 基本用途:組織數(shù)據(jù)
  • 常見操作:插入屎篱、刪除服赎、排序、搜索交播、遍歷等
  • 不同的數(shù)據(jù)結(jié)構(gòu)重虑,適合解決不同的問題

每種結(jié)構(gòu)要了解什么知識(shí)點(diǎn)

  • 用途與定義 eg. HashSet可以用來查看
  • 常見功能及復(fù)雜度 eg. BST查找元素復(fù)雜度O(log(N))
  • 實(shí)現(xiàn)原理 e.g. HashMap的沖突解決策略: Linear Probing / Separate Chaining
  • 注意事項(xiàng) e.g. 翻轉(zhuǎn)鏈表(Iterative/Recursive)
  • 語(yǔ)言細(xì)節(jié) e.g. Java中heap是用什么class實(shí)現(xiàn)的?

Big O

一種算法有多“快”?
某種數(shù)據(jù)結(jié)構(gòu)或算法所支持的操作,有其時(shí)間、空間上的“效率 “秦士。我們用時(shí)間/空間復(fù)雜度這個(gè)概念來衡量它嚎尤。
時(shí)間復(fù)雜度,是指算法運(yùn)行時(shí)間與輸入數(shù)據(jù)量的函數(shù)關(guān)系,常用 大寫字母O表示,讀作Big Oh。
類似地,空間復(fù)雜度,是指算法運(yùn)行空間與輸入數(shù)據(jù)量的函數(shù)關(guān) 系伍宦。
復(fù)雜度不僅有Big O一種表達(dá)方式,Big O最常見。 詳參《算法導(dǎo)論》

常見時(shí)間復(fù)雜度種類

  1. O(1) 表明算法運(yùn)行時(shí)間不隨輸入數(shù)據(jù)量增長(zhǎng)而變化,一直保持恒定乏梁。 e.g. HashSet/HashMap的contains(E elem)方法
  2. O(N)
    表明算法運(yùn)行時(shí)間與輸入數(shù)據(jù)量增長(zhǎng)呈線性相關(guān)次洼。 e.g. Unordered Array的查找。
  3. O(logN)
    表明算法運(yùn)行時(shí)間與輸入數(shù)據(jù)量增長(zhǎng)呈對(duì)數(shù)關(guān)系:k^x = N遇骑。
    e.g. Heap的pop操作卖毁。該復(fù)雜度常見于平衡的樹結(jié)構(gòu)操作或二分查找,即“一次去掉一半“。
  4. O(N^2) 表明算法運(yùn)行時(shí)間與輸入數(shù)據(jù)量增長(zhǎng)呈平方(Quadratic)關(guān)系。 e.g. for...for...; Bubble Sort
    5. O(NlogN)
    通常出現(xiàn)于O(log N)操作執(zhí)行了N次,或O(N)操作執(zhí)行了log N次亥啦。 e.g. HeapSort, MergeSort
  5. O(2^N)
    較低效,應(yīng)當(dāng)盡力避免炭剪。
    e.g. 斐波那契數(shù)列的遞歸實(shí)現(xiàn)。
public int Fibonacci(n) {
    if (n == 1 || n == 2)
        return 1;
    if (n > 2)
return Fibonacci(n-1) + Fibonacci(n-2);
}
  1. O(N!) 比指數(shù)時(shí)間更低效,應(yīng)當(dāng)避免翔脱。 e.g. Permutation

Big O 注意事項(xiàng)

  1. BigO表示函數(shù)關(guān)系,是相對(duì)量,不是絕對(duì)量
    e.g. 時(shí)間復(fù)雜度數(shù)量級(jí)小,不等于絕對(duì)速度在任何情況下都更快,只表明運(yùn)行時(shí)間隨
    輸入數(shù)據(jù)量的變化速度較慢或不變奴拦。
  2. 只取變化量最大的關(guān)系,省略其他
    e.g. O(N^2 + 2*N)等同于O(N^2)
  3. 通常取最壞情況
    e.g. 假設(shè)在隊(duì)列頭部插入,而非中部或尾部
    e.g. 平均情況? “一般是在哪里插入”
  4. O(N!)比指數(shù)復(fù)雜度更低效

線性結(jié)構(gòu)

Array

數(shù)組是一種按照線性的順序來組織固定數(shù)量 (fixed amount)的數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)。
數(shù)組所儲(chǔ)存的單個(gè)數(shù)據(jù)稱為數(shù)組的元素(element)
Java中,Array只能裝一種元素,但可以是primary type,也可以 是object届吁。
注意事項(xiàng):

  1. Fixed size, not dynamic
    注意防止溢出
  2. No holes:無洞性
    刪除后必須把后面的元素向前移错妖,插入同理
    復(fù)雜度
    | Tables | Are | Cool |
    | ------------- |:-------------:| -----:|
    | col 3 is | right-aligned | $1600 |
    | col 2 is | centered | $12 |
    | zebra stripes | are neat | $1 |
操作 時(shí)間復(fù)雜度
插入/刪除(原地) O(N)
搜索(未排序) O(N)
搜索(已排序) O(log N)
定位 arr[1] O(1)
遍歷 O(N)
排序 O(N log N)

ArrayList

Dynamic array 既能完成數(shù)組線性儲(chǔ)存、管理疚沐、常數(shù)時(shí)間 內(nèi)定位數(shù)據(jù)的功能,又可以自動(dòng)調(diào)整數(shù)組長(zhǎng)度暂氯。
Java中,這一功能由ArrayList來實(shí)現(xiàn)。

復(fù)雜度

操作 時(shí)間復(fù)雜度
插入/刪除(原地) O(N)
插入/刪除(動(dòng)態(tài)) Enabled, O(N)
搜索(未排序) O(N)
搜索(已排序) O(log N)
定位 arr[1] O(1)
遍歷 O(N)
排序 O(N log N)

復(fù)雜度同Array亮蛔,不同點(diǎn)是支持動(dòng)態(tài)插入刪除

操作 時(shí)間復(fù)雜度
插入/刪除(原地) O(N)
插入/刪除(動(dòng)態(tài)) Enabled, O(N)
搜索(未排序) O(N)
搜索(已排序) O(log N)
定位 arr[1] O(1)
遍歷 O(N)
排序 O(N log N)

擴(kuò)容公式

New Capacity = max(新arraylist的最小長(zhǎng)度,原 arraylist的size * 2)

LinkedList

只要有插入/刪除點(diǎn)的引用(指針),即可實(shí)現(xiàn)O(1)插入/刪除

復(fù)雜度

操作 時(shí)間復(fù)雜度
插入/刪除(有指針) O(1)
插入/刪除(用index) O(N)
搜索 O(N)
定位 O(N)
遍歷 O(N)
排序 O(N log N)

經(jīng)典題目:翻轉(zhuǎn)鏈表

public ListNode reverseList(ListNode head) {
     if (head == null || head.next == null) return head;
     ListNode prev = null, cur = head;
     ListNode next;
     while (cur != null) {
          next = cur.next;
          cur.next = prev;
          prev = cur;
          cur = next; }
     return prev;
}

Java鏈表為雙向鏈表痴施,實(shí)現(xiàn)類?

Stack

操作 時(shí)間復(fù)雜度
彈出頂部元素 pop O(1)
放元素至頂部 push O(1)
查看是否為空 O(1)
窺看頂部元素 peek O(1)
搜索 O(N)
定位 Disabled
遍歷 O(N)

棧(Stack)是一種以O(shè)(1)復(fù)雜度實(shí)現(xiàn)LIFO(Last In First Out)功能的線性數(shù)據(jù)結(jié)構(gòu)

操作 時(shí)間復(fù)雜度
彈出頂部元素 pop O(1)
放元素至頂部 push O(1)
查看是否為空 O(1)
窺看頂部元素 peek O(1)
搜索 O(N)
定位 Disabled
遍歷 O(N)

Queue

操作 時(shí)間復(fù)雜度
進(jìn)入隊(duì)尾 enqueue O(1)
彈出隊(duì)首 dequeue O(1)
窺視隊(duì)首 peek O(1)
搜索 O(N)
定位 Disabled
遍歷 O(N)

隊(duì)列(Queue)是一種以O(shè)(1)復(fù)雜度實(shí)現(xiàn)LIFO(First In Last Out)功能的線性數(shù)據(jù)結(jié)構(gòu)

操作 時(shí)間復(fù)雜度
進(jìn)入隊(duì)尾 enqueue O(1)
彈出隊(duì)首 dequeue O(1)
窺視隊(duì)首 peek O(1)
搜索 O(N)
定位 Disabled
遍歷 O(N)

Java中究流,Queue是一個(gè)接口,有多種實(shí)現(xiàn)辣吃。 常用的初始化方式:
1.LinkedList
2.PriorityQueue(見Heap)

經(jīng)典題目

1.用Stack實(shí)現(xiàn)Queue
2.用Queue實(shí)現(xiàn)Stack

Tree

樹是節(jié)點(diǎn)(node)的集合。這些節(jié)點(diǎn)用父子關(guān)系來儲(chǔ)存元素梯嗽,其中:根節(jié)點(diǎn)沒有父節(jié)點(diǎn),其他節(jié)點(diǎn)有且只有一個(gè)父節(jié)點(diǎn)齿尽。
樹的結(jié)構(gòu)越接近一個(gè)鏈條,各操作就越接近線性結(jié)構(gòu)灯节,就失去了樹結(jié)構(gòu)的優(yōu)勢(shì)循头。
常見二叉樹:二叉搜索樹(Binary Search Tree,BST) 常見多叉樹:字典樹(Trie Tree炎疆,通常為26叉樹)

二叉搜索樹(Binary Search Tree)

二叉搜索樹是一種二叉樹,能夠按順序組織元素卡骂。 滿足以下條件:

  1. 每一個(gè)節(jié)點(diǎn)的左子樹中的元素,比這個(gè)節(jié)點(diǎn)的 元素小,或與它相等。
  2. 每一個(gè)節(jié)點(diǎn)的右子樹中的元素,比這個(gè)節(jié)點(diǎn)的 元素大,或與它相等形入。
    進(jìn)行In-Order Traversal時(shí),順序從小到大全跨。
    BST適合用來對(duì)元素排序,或維護(hù)元素順序。 大多數(shù)關(guān)于樹的常見面試題目與二叉搜索樹有關(guān)亿遂。

二叉搜索樹可分為平衡樹(Balanced Tree)與非平衡樹浓若。 “平衡”指樹形相對(duì)“扁平”。如AVL樹:父節(jié)點(diǎn)的左右子樹均為平衡樹,且高度 之差<=1蛇数。
“自平衡樹”:時(shí)刻維持樹的平衡挪钓。不同自平衡樹有不同的自平衡策略。AVL是一種常見的自平衡二叉查找樹耳舅,當(dāng)AVL檢測(cè)到不平衡的狀況出現(xiàn)碌上,它會(huì)旋轉(zhuǎn)樹節(jié)點(diǎn),使得樹重新平衡。
為何要區(qū)分平衡樹與非平衡樹? 為保證插入馏予、刪除天梧、搜索的最壞時(shí)間復(fù)雜度不高于O(log N)
AVL平衡二叉樹,插入、刪除霞丧、搜索時(shí)間復(fù)雜度為O(logN)呢岗,遍歷為O(N)
樹的遍歷:
1.Depth-First Search
1.Breath-First Search
二叉樹題目總結(jié)

AVL tree VS Red-Black Tree
The AVL trees are more balanced compared to Red Black Trees, but they may cause more rotations during insertion and deletion. So if your application involves many frequent insertions and deletions, then Red Black trees should be preferred. And if the insertions and deletions are less frequent and search is more frequent operation, then AVL tree should be preferred over Red Black Tree.
Red-Black Tree

Graph

“圖”(Graph):節(jié)點(diǎn)的集合 + 連接這些節(jié)點(diǎn)的邊的集合。 在圖論中,樹(Tree)是一種無向圖(Undirected Graph),其中任意兩個(gè)頂點(diǎn)間存在唯一一條路徑蚯妇》罅牵或者說,只要沒有環(huán)(cycle)的連通圖(亦即沒有島island)就是樹。

Heap

Heap是一種邏輯結(jié)構(gòu)為樹形箩言,物理結(jié)構(gòu)為線性的數(shù)據(jù)結(jié)構(gòu),它的主要功能是維護(hù)及提供最小或最大元素(依此分為最小堆和最大堆)硬贯。

  • 近完全的樹形結(jié)構(gòu)(almost complete Tree):除最后一層外,每層都維持“滿節(jié) 點(diǎn)”狀態(tài)。添加元素時(shí),從左到右依次添 加陨收。
  • 根節(jié)點(diǎn)存放最小(或最大)元素饭豹。
  • 對(duì)每個(gè)節(jié)點(diǎn)而言,其子節(jié)點(diǎn)的元素值都比自己小(或大)。


    image.png

物理結(jié)構(gòu)

為什么說Heap的物理結(jié)構(gòu)是線性的务漩?


image.png

[0,99,13,81,1,12,78]
1.對(duì)于任意一個(gè)index為k的節(jié)點(diǎn):

  • 其父節(jié)點(diǎn)的index:k/2
  • 其左孩子的index:2*k
  • 其右孩子的index:2*k+1
    2.index為0的位置要空出來

建堆

逐個(gè)offer法 O(NlogN)
逐層掃描法 O(N)

重點(diǎn)

  1. 用途是維護(hù)和提供最大最小值,但不負(fù)責(zé)完整排序拄衰。
  2. 物理線性,邏輯樹形(近完全樹)。
  3. 兩個(gè)操作:彈出最值和加入新元素,復(fù)
    雜度都是O(log N)饵骨。
  4. 建堆時(shí)間可以優(yōu)化到O(N)翘悉。
  5. 非葉節(jié)點(diǎn)index:1 - n/2。
  6. Java中可直接調(diào)用PriorityQueue類使用其功能居触。

Set/Map

沖突問題(Collision)

不同的key形成了同一個(gè)hash碼
為何會(huì)有沖突問題

  • 哈希函數(shù)的特性妖混。e.g.“均勻哈希函數(shù)”(Uniform Hash function)
  • 存儲(chǔ)位置比較少
    沖突問題如何解決?
  1. Separate Chaining(鏈接法)
  • 以每個(gè)bucket內(nèi)的Entry object為head node,將不同的entry連綴起來形成 LinkedList。(即每個(gè)bucket是一個(gè)鏈表轮洋,可以動(dòng)態(tài)增刪)
  • 插入時(shí),查找一遍已存在的LinkedList,如果有相同的key則更新其value;如果沒有, 則插入到bucket首位制市。
  • 刪除、查找時(shí)同理弊予。
  1. Linear Probing(線性探查)

定義

Map是一種為“Key-value pair” 提供存儲(chǔ)祥楣、查找、替換汉柒、遍歷等功能的數(shù)據(jù)結(jié)構(gòu)误褪。

實(shí)現(xiàn)方式

Map interface
  • HashMap is implemented as a hash table, and there is no ordering on keys or values.
  • TreeMap is implemented based on red-black tree structure, and it is ordered by the key.
  • LinkedHashMap preserves the insertion order
  • Hashtable is synchronized, in contrast to HashMap. It has an overhead for synchronization.
  • This is the reason that HashMap should be used if the program is thread-safe.

參考:四種基本實(shí)現(xiàn)
根據(jù)常見實(shí)現(xiàn)方式可以分為: HashMap, TreeMap, LinkedHashMap

  • LinkeHashMap: HashMap + LinkedList, 可以保存輸入的順序
    Application: LRU Cache
  • TreeMap:HashMap + 紅黑樹(自平衡的BST),可以針對(duì)可排序的key進(jìn)行排序碾褂,key為自定義對(duì)象是必須實(shí)現(xiàn)Comparable接口
  • HashTable:The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls. HashTable的所有接口都是synchronized
  • HashMap提供了最快的查找技術(shù)兽间,也沒有按照任何明顯的順序來保存元素。TreeMap按照比較結(jié)果的升序保存鍵斋扰,而LinkedHashMap則按照插入順序保存鍵,同時(shí)還保留了HashMap的查詢速度。
    如果Map的key是自定義對(duì)象传货,需要自己實(shí)現(xiàn)equals() 和 hashCode()屎鳍,否則會(huì)使用默認(rèn)的equals() 和 hashCode()

The default hashCode() method gives distinct integers for distinct objects, and the equals() method only returns true when two references refer to the same object.

Set(集合)

主要用途: 查找(查重)

實(shí)現(xiàn)方式

根據(jù)實(shí)現(xiàn)方式也分為: HashSet, TreeSet,LinkedHashSet
HashSet提供了最快的查找技術(shù)问裕,存儲(chǔ)的順序沒有實(shí)際的意義逮壁。TreeMap按照比較結(jié)果的升序保存對(duì)象,而LinkedHashMap則按照插入順序保存對(duì)象粮宛。
底層結(jié)構(gòu):

  1. 用一個(gè)HashMap來實(shí)現(xiàn),但value部 分用dummy object,只保留key
  2. 存儲(chǔ)和查找原理與HashMap完全一致
  3. 如果重復(fù),和HashMap一樣會(huì)替換,但因?yàn)関alue都是dummy
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末窥淆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子巍杈,更是在濱河造成了極大的恐慌忧饭,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件筷畦,死亡現(xiàn)場(chǎng)離奇詭異词裤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)鳖宾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門吼砂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鼎文,你說我怎么就攤上這事渔肩。” “怎么了拇惋?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵周偎,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我蚤假,道長(zhǎng)栏饮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任磷仰,我火速辦了婚禮袍嬉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘灶平。我一直安慰自己伺通,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布逢享。 她就那樣靜靜地躺著罐监,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瞒爬。 梳的紋絲不亂的頭發(fā)上弓柱,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天沟堡,我揣著相機(jī)與錄音,去河邊找鬼矢空。 笑死航罗,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的屁药。 我是一名探鬼主播粥血,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼酿箭!你這毒婦竟也來了复亏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤缭嫡,失蹤者是張志新(化名)和其女友劉穎缔御,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體械巡,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡刹淌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了讥耗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片有勾。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖古程,靈堂內(nèi)的尸體忽然破棺而出蔼卡,到底是詐尸還是另有隱情,我是刑警寧澤挣磨,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布雇逞,位于F島的核電站,受9級(jí)特大地震影響茁裙,放射性物質(zhì)發(fā)生泄漏塘砸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一晤锥、第九天 我趴在偏房一處隱蔽的房頂上張望掉蔬。 院中可真熱鬧,春花似錦矾瘾、人聲如沸女轿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蛉迹。三九已至,卻和暖如春放妈,著一層夾襖步出監(jiān)牢的瞬間北救,已是汗流浹背荐操。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留珍策,地道東北人淀零。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像膛壹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子唉堪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容