鏈表和樹是面試中出現頻率最高的數據結構。由於操作鏈表和樹需要操作大量的指針,應聘者在解決相關問題的時候一定要留意代碼的魯棒性,否則容易出現程序崩潰的問題。棧是一個與遞歸緊密相關的數據結構,同樣隊列也與廣度優先遍歷算法緊密相關。深刻理解這兩種數據結構能幫助我們解決很多算法問題
數組
- 數組中的內存是連續的,可以根據下標在 O(1) 時間 讀、寫 任何元素,時間效率高,因此可以用來實現簡單的哈希表
- 爲了解決數組空間效率不高的問題,人們設計了多種動態數組,比如C++的STL中的vector
- 數組的名字也是一個指針,指向數組的第一個元素
- 在32位系統上,對任意指針求sizeof,結果都是4
#include <stdio.h>
int main()
{
int data1[] = {1,2,3};
//求數組的大小,答案是12
int size1 = sizeof(data1);
int* data2 = data1;
//求指針的大小,答案是4
int size2 = sizeof(data2);
printf("%d, %d",size1,size2);
}
字符串
- 連續內存存字符,每個字符串都以字符 ‘\0’ 結尾,方便找到字符串的尾部,但要記住字符串有一個額外字符的開銷,注意避免越界
- 爲了節省內存,C/C++把常量字符串放到單獨的一個內存區域。當幾個指針賦值給相同的常量字符串時,它們實際上會指向相同的內存地址
- 下面這個例子裏,str1和str2是兩個字符串數組,初始地址不同,所以第一個輸出not same, str3和str4是兩個指針,不需要分配內存來存儲字符串,只需要指向同一個常量字符串的地址,所以輸出same
#include <stdio.h>
int main()
{
char str1[] = "hello";
char str2[] = "hello";
char* str3 = "hello";
char* str4 = "hello";
if(str1 == str2)
printf("same\n");
else
printf("not same\n");
if(str3 == str4)
printf("same\n");
else
printf("not same\n");
}
樹
- 樹:除了根結點之外每個結點只有一個父結點,根結點沒有父結點;除了葉結點之外所有結點都有一個或多個子結點,葉結點沒有子結點
- 二叉樹:樹的特殊結構,每個結點最多只能有兩個子結點。二叉樹特例有二叉搜索數、堆、紅黑樹
- 二叉搜索樹:左子結點總是小於或等於根結點,而右子結點總是大於或等於根結點,平均在 O(logn) 的時間內根據數值在二叉搜索樹中找到一個結點
- 堆:分爲最大堆和最小堆。在最大堆中根結點的值最大,在最小堆中根結點的值最小,解決快速找到最大值或者最小值的問題
- 紅黑樹:樹中的結點定義爲紅、黑兩種顏色,並通過規則確保從根結點到葉結點的最長路徑的長度不超過最短路徑的兩倍。在C++的STL中,set、multiset、map、multimap等數據結構都是基於紅黑樹實現的
棧和隊列
- 操作系統會給每個線程創建一個棧用來存儲函數調用時各個函數的參數、返回地址及臨時變量等
- 通常棧是一個不考慮排序的數據結構,我們需要 O(n) 時間才能找到棧中最大或者最小的元素
- 棧:後進先出
- 隊列:先進先出