1. 程式人生 > >面試-8種 常用資料結構總結

面試-8種 常用資料結構總結

1976年,一個瑞士電腦科學家寫一本書《Algorithms + Data Structures = Programs》。即:演算法 + 資料結構 = 程式。40多年過去了,這個等式依然成立。

很多程式碼面試題都要求候選者深入理解資料結構,不管你來自大學計算機專業還是程式設計培訓機構,也不管你有多少年程式設計經驗。有時面試題會直接提到資料結構,比如“給我實現一個二叉樹”,然而有時則不那麼明顯,比如“統計一下每個作者寫的書的數量”。

什麼是資料結構?

資料結構是計算機儲存、組織資料的方式。對於特定的資料結構(比如陣列),有些操作效率很高(讀某個陣列元素),有些操作的效率很低(刪除某個陣列元素)。程式設計師的目標是為當前的問題選擇最優的資料結構。

為什麼我們需要資料結構?

資料是程式的核心要素,因此資料結構的價值不言而喻。無論你在寫什麼程式,你都需要與資料打交道,比如員工工資、股票價格、雜貨清單或者電話本。在不同場景下,資料需要以特定的方式儲存,我們有不同的資料結構可以滿足我們的需求。

8種常用資料結構

  1. 陣列
  2. 佇列
  3. 連結串列
  4. 字首樹
  5. 雜湊表

1. 陣列

陣列(Array)大概是最簡單,也是最常用的資料結構了。其他資料結構,比如棧和佇列都是由陣列衍生出來的。

下圖展示了1個數組,它有4個元素:

每一個數組元素的位置由數字編號,稱為下標或者索引(index)。大多數程式語言的陣列第一個元素的下標是0。

根據維度區分,有2種不同的陣列:

  • 一維陣列(如上圖所示)
  • 多維陣列(陣列的元素為陣列)

陣列的基本操作

  • Insert - 在某個索引處插入元素
  • Get - 讀取某個索引處的元素
  • Delete - 刪除某個索引處的元素
  • Size - 獲取陣列的長度

常見陣列程式碼面試題

2. 棧

撤回,即Ctrl+Z,是我們最常見的操作之一,大多數應用都會支援這個功能。你知道它是怎麼實現的嗎?答案是這樣的:把之前的應用狀態(限制個數)儲存到記憶體中,最近的狀態放到第一個。這時,我們需要棧(stack)

來實現這個功能。

棧中的元素採用LIFO (Last In First Out),即後進先出

下圖的棧有3個元素,3在最上面,因此它會被第一個移除:

棧的基本操作

  • Push — 在棧的最上方插入元素
  • Pop — 返回棧最上方的元素,並將其刪除
  • isEmpty — 查詢棧是否為空
  • Top — 返回棧最上方的元素,並不刪除

常見的棧程式碼面試題

 

記憶體中的堆疊和資料結構堆疊不是一個概念,可以說記憶體中的堆疊是真實存在的物理區,資料結構中的堆疊是抽象的資料儲存結構。
1.記憶體中的堆疊
    1)暫存器:最快的儲存區, 由編譯器根據需求進行分配,我們在程式中無法控制. 
    2)棧:存放基本型別的變數資料和物件的引用,但物件本身不存放在棧中,而是存放在堆(new 出來的物件)或者常量池中(字串常量物件存放在常量池中。) 
    3)堆:存放所有new出來的物件。 
    4)靜態域:存放靜態成員(static定義的) 
    5)常量池:存放字串常量和基本型別常量(public static final)。 
    6)非RAM儲存:硬碟等永久儲存空間 
記憶體空間在邏輯上分為三部分:程式碼區、靜態資料區和動態資料區,動態資料區又分為棧區和堆區。
程式碼區:儲存方法體的二進位制程式碼。高階排程(作業排程)、中級排程(記憶體排程)、低階排程(程序排程)控制程式碼區執行程式碼的切換。
靜態資料區:儲存全域性變數、靜態變數、常量,常量包括final修飾的常量和String常量。系統自動分配和回收。
棧區:儲存執行方法的形參、區域性變數、返回值。由系統自動分配和回收。
例如 int method(int a){int b;}棧中儲存引數a、區域性變數b、返回值temp。
堆區:new一個物件的引用或地址儲存在棧區,指向該物件儲存在堆區中的真實資料。由程式設計師分配和回收(Java中由JVM虛擬機器的垃圾回收機制自動回收)。
例如 Class Student{int num; int age;} main方法中Student stu = new Student();分配堆區空間中儲存的該物件的num、age,變數stu儲存在棧中,裡面的值是對應堆區空間的引用或地址。

2.資料結構中的堆疊
棧:是一種連續儲存的資料結構,特點是儲存的資料先進後出。
堆:是一棵完全二叉樹結構,特點是父節點的值大於(小於)兩個子節點的值(分別稱為大頂堆和小頂堆)。它常用於管理演算法執行過程中的資訊,應用場景包括堆排序,優先佇列等。

3. 佇列

佇列(Queue)與棧類似,都是採用線性結構儲存資料。它們的區別在於,棧採用LIFO方式,而佇列採用先進先出,即FIFO(First in First Out)

下圖展示了一個佇列,1是最上面的元素,它會被第一個移除:

佇列的基本操作

  • Enqueue — 在佇列末尾插入元素
  • Dequeue — 將佇列第一個元素刪除
  • isEmpty — 查詢佇列是否為空
  • Top — 返回佇列的第一個元素

常見的佇列程式碼面試題

4. 連結串列

連結串列(Linked List)也是線性結構,它與陣列看起來非常像,但是它們的記憶體分配方式、內部結構和插入刪除操作方式都不一樣。

連結串列是一系列節點組成的鏈,每一個節點儲存了資料以及指向下一個節點的指標。連結串列頭指標指向第一個節點,如果連結串列為空,則頭指標為空或者為null。

連結串列可以用來實現檔案系統、雜湊表和鄰接表。

下圖展示了一個連結串列,它有3個節點:

連結串列分為2種:

  • 單向連結串列
  • 雙向連結串列

連結串列的基本操作

  • InsertAtEnd — 在連結串列結尾插入元素
  • InsertAtHead — 在連結串列開頭插入元素
  • Delete — 刪除連結串列的指定元素
  • DeleteAtHead — 刪除連結串列第一個元素
  • Search — 在連結串列中查詢指定元素
  • isEmpty — 查詢連結串列是否為空

常見的佇列程式碼面試題

5. 圖

圖(graph)由多個節點(vertex)構成,節點之間闊以互相連線組成一個網路。(x, y)表示一條邊(edge),它表示節點x與y相連。邊可能會有權值(weight/cost)

圖分為兩種:

  • 無向圖
  • 有向圖

在程式語言中,圖有可能有以下兩種形式表示:

  • 鄰接矩陣(Adjacency Matrix)
  • 鄰接表(Adjacency List)

遍歷圖有兩週演算法

  • 廣度優先搜尋(Breadth First Search)
  • 深度優先搜尋(Depth First Search)

常見的圖程式碼面試題

6. 樹

樹(Tree)是一個分層的資料結構,由節點和連線節點的邊組成。樹是一種特殊的圖,它與圖最大的區別是沒有迴圈。

樹被廣泛應用在人工智慧和一些複雜演算法中,用來提供高效的儲存結構。

下圖是一個簡單的樹以及與樹相關的術語:

樹有很多分類:

  • N叉樹(N-ary Tree)
  • 平衡樹(Balanced Tree)
  • 二叉樹(Binary Tree)
  • 二叉查詢樹(Binary Search Tree)
  • 平衡二叉樹(AVL Tree)
  • 紅黑樹(Red Black Tree)
  • 2-3樹(2–3 Tree)

其中,二叉樹和二叉查詢樹是最常用的樹。

常見的樹程式碼面試題

7. 字首樹

字首樹(Prefix Trees或者Trie)與樹類似,用於處理字串相關的問題時非常高效。它可以實現快速檢索,常用於字典中的單詞查詢,搜尋引擎的自動補全甚至IP路由。

下圖展示了“top”, “thus”和“their”三個單詞在字首樹中如何儲存的:

單詞是按照字母從上往下儲存,“p”, “s”和“r”節點分別表示“top”, “thus”和“their”的單詞結尾。

常見的樹程式碼面試題

8. 雜湊表

雜湊(Hash)將某個物件變換為唯一識別符號,該識別符號通常用一個短的隨機字母和數字組成的字串來代表。雜湊可以用來實現各種資料結構,其中最常用的就是雜湊表(hash table)

雜湊表通常由陣列實現。

雜湊表的效能取決於3個指標:

  • 雜湊函式
  • 雜湊表的大小
  • 雜湊衝突處理方式

下圖展示了有陣列實現的雜湊表,陣列的下標即為雜湊值,由雜湊函式計算,作為雜湊表的鍵(key),而陣列中儲存的資料即為值(value)

常見的雜湊表程式碼面試題

參考

關於Fundebug

Fundebug專注於JavaScript、微信小程式、微信小遊戲、支付寶小程式、React Native、Node.js和Java實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了9億+錯誤事件,得到了Google、360、金山軟體等眾多知名使用者的認可。歡迎免費試用!

版權宣告:
轉載時請註明作者Fundebug以及本文地址:
https://blog.fundebug.com/2018/08/27/code-interview-data-structure/