數據結構與算法之基礎知識

微信搜一搜「bigsai」一直分享乾貨
文章已收錄在 個人Github bigsai-algorithmjava

前言

數據結構與算法是程序員內功體現的重要標準之一,且數據結構也應用在各個方面,業界更有程序=數據結構+算法這個等式存在。各個中間件開發者,架構師他們都在努力的優化中間件、項目結構以及算法提升運行效率和下降內存佔用,在這裏數據結構起到至關重要的做用。此外數據結構也蘊含一些面向對象的思想,故學好掌握數據結構對邏輯思惟處理抽象能力有很大提高。git

爲何學習數據結構與算法?若是你仍是學生,那麼這門課程是必修的,考研基本也是必考科目。工做在內卷嚴重的大廠中找工做數據結構與算法也是面試、筆試必備的很是重要的考察點。若是工做了數據結構和算法也是內功提高一個很是重要的體現,對於程序員來講,想要獲得滿意的結果,數據結構與算法是必備功力!程序員

數據結構

image-20201108002732048

概念

數據結構是計算機存儲、組織數據的方式。數據結構是指相互之間存在一種或多種特定關係的數據元素的集合。一般狀況下,精心選擇的數據結構能夠帶來更高的運行或者存儲效率。github

簡言之,數據結構是一系列的存儲結構按照必定執行規則、配合必定執行算法所造成的高效的存儲結構。在咱們所熟知的關係數據庫、非關係數據庫、搜索引擎存儲、消息隊列等都是比較牛的大型數據結構良好的運用。固然這些應用中間件不僅僅要考慮單純的結構問題。還考慮實際os、網絡等其餘因素。面試

而對於數據結構與算法這個專欄。咱們程序員更改掌握的首先是在內存中運行的抽象的數據結構。是一個相對比較單一的數據結構類型,好比線性結構等等.算法

相關術語

在數據結構與算法中,數據、數據對象、數據元素、數據項不少人搞不清其中的關係。經過畫一張圖來捋一捋,而後下面舉個例子給你們分享一下。數據庫

image-20201230101757854

用戶信息表usersapi

id name sex
001 bigsai man
002 smallsai man
003 菜虛鯤 woman

users的pojo對象數組

class users
{ 
     //略
     int id;
     String name;
     String sex;
}
//list和woman是數據
List<users>list;//數據對象list
List<users>woman;//數據對象woman
list.add(new users(001,"bigsai","man"));//添加數據元素 一個users由(001,bigsai,man)三個數據項組成 
list.add(new users(002,"smallsai","man"));//數據元素
list.add(new users(003,"菜虛鯤","woman"));//數據元素
woman.add(list.get(2));//003,"菜虛鯤","woman"三個數據項構成的一個數據元素

數據:對客觀事物的符號表示,指全部能輸入到計算機中並被計算機程序處理的符號的集合總稱。上述表中的三條用戶信息的記錄就是數據(也可能多表多集合這裏只有一個)。這些數據通常都是用戶輸入或者是自定義構造完成。固然,還有一些圖像、聲音也是數據。微信

數據元素:數據元素是數據的基本單位。一個數據元素由若干數據項構成!可認爲是一個pojo對象、或者是數據庫的一條記錄。好比菜虛鯤那條記錄就是一個數據元素。

數據項: 而構成用戶字段/屬性的有idnamesex等,這些就是數據項.數據項是構成數據元素的最小不可分割字段。能夠看做一個pojo對象或者一張表(people)的一個屬性/字段的值。

數據對象:是相同性質數據元素的集合。是數據的一個子集。好比上面的users表、list集合、woman集合都是數據對象。單獨一張表,一個集合均可以是一個數據對象。

總的捋一捋,數據範圍最廣,全部數據即數據,而數據對象僅僅是有相同性質的一個集合,這個集合是數據的子集,但並非數據的基本單位,而數據元素纔是數據的基本單位。舉個例子表cat和表dog都是數據,而後表cat是個數據對象(由於都描述cat這種對象),可是數據的基本單位並非貓和狗,而是他們的具體的每一條,好比小貓咪1號,大貓咪二號,哈士奇1號,藏獒2號這些每一條纔是數據的基本單位。

還有數據類型,抽象數據類型也在下面講一講。

數據類型

原子類型:其值不可再分的類型。好比int,char,double,float等。

結構類型:其值能夠再分爲若干成分的數據類型。好比結構體構造的各類結構等。

抽象數據類型(ADT):抽象數據類型(ADT)是一個實現包括儲存數據元素的存儲結構以及實現基本操做的算法。使得只研究和使用它的結構而不用考慮它的實現細節成爲可能。好比咱們使用List、Map、Set等等只須要了解它的api和性質功能便可。而具體的實現多是不一樣的方案,好比List的實現有數組和鏈表不一樣選擇。

三要素

邏輯結構:數據元素之間的邏輯關係。邏輯結構分爲線性結構非線性結構。線性結構就是順序表、鏈表之類。而非線性就是集合、樹、圖這些結構。

存儲結構:數據結構在計算機中的表示(又稱映像,也稱物理結構),存儲結構主要分爲順序存儲鏈式存儲索引存儲散列(哈希)存儲,這幾種存儲經過下面這張圖簡單瞭解一下(僅僅爲理解不考慮更多):

image-20201230110548234

數據的運算:施加在數據上的運算包括運算的定義實現,運算的定義基於邏輯結構,運算的實現基於存儲結構。

在這裏容易混淆的是邏輯結構與存儲結構的概念。對於邏輯結構,不難看得出邏輯二字,邏輯關係也就是二者存在數據上的關係而不考慮物理地址的關係,好比線性結構和非線性結構,它描述的是一組數據中聯繫的方式和形式,他針對的是數據。看中的是數據結構的功能,好比線性表就是先後有序的,我須要一個有序的集合就可使用線性表。

存儲結構就是跟物理地址掛鉤的。由於一樣邏輯結構採用不一樣存儲結構實現適用場景和性能可能不一樣。好比一樣是線性表,可能有多種存儲結構的實現方式。好比順序表鏈表(Arraylist,Linkedlist)它們的存儲結構就不一樣,一個是順序存儲(數組)實現,一個是鏈式存儲(鏈表)實現。它關注的是計算機運行物理地址的關係。但一般同一類存儲結構實現的一些數據結構有一些相似的共同點和缺點(線性易查難插、鏈式易插難查等等)。

算法分析

上面講了數據結構相關概念,下面對算法分析的一些概念進行描述。

在這裏插入圖片描述

算法的五個重要特徵:有窮性、肯定性、可行性、輸入、輸出。這些從字面意思便可理解,其中有窮性強調算法要有結束的時候不能無限循環;而肯定性是每條指令有它意義,相同的輸入獲得相同的輸出;可行性是指算法每一個步驟通過若干次執行能夠實現;輸入是0個或多個輸入(可0);輸出是1個或多個輸出(必定要有輸出)。

而一個好的算法,一般更要着重考慮的是效率和空間資源佔用(時間複雜度和空間複雜度),一般複雜度更多描述的是一個量級程度而不多用具體數字描述。

空間複雜度

概念:是對一個算法在運行過程當中臨時佔用存儲空間大小的量度,記作S(n)=O(f(n))

空間複雜度其實在算法的衡量佔比是比較低的(咱們常用犧牲空間換時間的數據結構和算法),可是不能忽視空間複雜度中重要性。不管在刷題仍是實際項目生產內存都是一個極大額指標。對於Java而言更是如此。自己內存就大,若是採用的存儲邏輯不太好會佔用更多的系統資源,對服務形成壓力。

而算法不少狀況都是犧牲空間換取時間(效率)。就好比咱們熟知的字符串匹配String.contains()方法,咱們都知道他是暴力破解,時間複雜度爲O(n^2),不須要藉助額外內存。而KMP算法在效率和速度上都原生暴力方法,可是KMP要藉助其餘數組(next[])進行標記儲存運算。就用到了空間開銷。再好比歸併排序也會藉助新數組在遞歸分冶的適合進行逐級計算,提升效率,但增長點影響不大的內存開銷。

固然,算法的空間花銷最大不能超過jvm設置的最大值,通常爲2G.(2147483645)若是開二維數組多種多維數據不要開的太大,可能會致使heap OutOfMemoryError

時間複雜度

概念:計算機科學中,算法的時間複雜度是一個函數,它定性描述了該算法的運行時間。這是一個關於表明算法輸入值的字符串的長度的函數。時間複雜度經常使用大O符號表述,不包括這個函數的低階項和首項係數。使用這種方式時,時間複雜度可被稱爲是漸近的,它考察當輸入值大小趨近無窮時的狀況。

時間複雜度的排序:O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) <O(n!) < O(n^n)

常見時間複雜度:對於時間複雜度,不少人的概念是比較模糊的。下面舉例子說明一些時間複雜度。

O(1): 常數函數

  • a=15

O(logn): 對數函數

  • for(int i=1;i<n;i*=2)
    分析:假設執行t次使得i=n;有2^t=n; t=log2~n,爲log級別時間複雜度爲O(logn)。
  • 還有典型的二分查找,拓展歐幾里得,快速冪等算法均爲O(logn)。屬於高效率算法。

O(n): 線性函數

  • for (int i=0;i<n;i++)
  • 比較常見,可以良好解決大部分問題。

O(nlogn):

  • for (int i=1;i<n;i++)
    for (int j=1;j<i;j*=2)
  • 常見的排序算法不少正常狀況都是nlogn,好比快排、歸併排序。這種算法效率大部分也還不錯。

O(n^2)

  • for(int i=0;i<n;i++)
    for(int j=0;j<i;j++)
  • 其實O(n2)的效率就不敢恭維了。對於大的數據O(n2)甚至更高次方的執行效果會不好。

固然若是一樣是n=10000.那麼不一樣時間複雜度額算法執行次數、時間也不一樣。

具體 n 執行次數
O(1) 10000 1
O(log2n) 10000 14
O( n^1/2) 10000 100
O(n) 10000 10000
O(nlog2 n) 10000 140000
O(n^2) 10000 100000000
O(n^3) 10000 1000000000000

下降算法複雜度有些會靠數據結構的特性和優點,好比二叉排序樹的查找,線段樹的動態排序等等,這些數據結構解決某些問題有些很是良好的性能。還有的是靠算法策略解決,好比一樣是排序,冒泡排序這種笨而簡單的方法就是O(n2),但快排、歸併等聰明方法就能O(nlogn)。要想變得更快,那就得掌握更高級的數據結構和更精巧的算法。

時間複雜度計算
時間複雜度計算通常步驟:一、找到執行次數最多的語句; 二、計算語句執行的數量級 ; 三、用O表示結果。而且有兩個規則:

加法規則: 同一程序下若是多個並列關係的執行語句那麼取最大的那個,eg:

T(n)=O(m)+O(n)=max(O(m),O(n)); 
T(n)=O(n)+O(nlogn)=max(O(n),O(nlogn))=O(nlogn);

乘法規則:循環結構,時間複雜度按乘法進行計算,eg:

T(n)=O(m)*O(n)=O(mn)
T(n)=O(m)*O(m)=O(m^2)(兩層for循環)

固然不少算法的時間複雜度還跟輸入的數據有關,分爲還會有最優時間複雜度(可能執行次數最少時),最壞時間複雜度(執行次數最少時),平均時間複雜度,這在排序算法中已經具體分析,但咱們一般使用平均時間複雜度來衡量一個算法的好壞。

數據結構與算法學習

捋過數據結構與算法基本概念的介紹,在學習數據結構與算法方面,我的把經典的數據結構與算法學習過程步驟寫在下面,但願能給你們一個參考:

數據結構

  • 單鏈表(帶頭結點、不帶頭結點)設計與實現(增刪改查),雙鏈表設計與實現

  • 棧設計與實現(數組和鏈表),隊列設計與實現(數組和鏈表)

  • 二叉樹概念學習,二叉樹前序、中序、後序遍歷遞歸、非遞歸實現 ,層序遍歷

  • 二叉排序樹設計與實現(插入刪除)

  • 堆(優先隊列、堆排序)

  • AVL(平衡)樹設計與實現(四種自旋方式理解實現)

  • 伸展樹、紅黑樹原理概念理解

  • B、B+原理概念理解

  • 哈夫曼樹原理概念理解(貪心策略)

  • 哈希(散列表)原理概念理解(幾種解決哈希衝突方式)

  • 並查集/不相交集合(優化和路徑壓縮)

  • 圖論拓撲排序

  • 圖論dfs深度優先遍歷、bfs廣度優先遍歷

  • 最短路徑Dijkstra算法、Floyd算法、spfa算法

  • 最小生成樹prim算法、kruskal算法

  • 其餘數據結構線段樹、後綴數組等等

經典算法

  • 遞歸算法(求階乘、斐波那契、漢諾塔問題)
  • 二分查找
  • 分治算法(快排、歸併排序、求最近點對等問題)
  • 貪心算法(使用較多,區間選點問題,區間覆蓋問題)
  • 常見動態規劃(LCS(最長公共子序列) LIS(最長上升子序列)揹包問題等等)
  • 回溯算法(經典八皇后問題、全排列問題)
  • 位運算常見問題(參考劍指offer和LeetCode問題)
  • 快速冪算法(快速求冪乘、矩陣快速冪)
  • kmp等字符串匹配算法
  • 一切其餘數論算法(歐幾里得、拓展歐幾里得、中國剩餘定理等等)

相信看完這篇文章,你應該對數據結構與算法有個不錯的認知。數據結構與算法有着很是密切的關聯,數據結構是爲了實現某種算法,算法是核心目的。學習數據結構與算法以前,能夠先參考書本或者博客先了解其功能,再研究其運行原理,再動手實戰(編寫數據結構或者相關題目)這樣層次漸進,想要深刻的學習數據結構與算法光理解是不行的,須要有大量代碼實戰纔可。而且這條路是沒有止境的,活到老,學到老,刷到老。

2021一塊兒加油!持續分享!歡迎關注個人技術公衆號:bigsai
image-20201114211553660

相關文章
相關標籤/搜索