1. 程式人生 > >數據結構學習總結(1)數據結構的認識

數據結構學習總結(1)數據結構的認識

序表 這樣的 mda 有時 循環語句 大小 增加 存儲 整除

當你決定看這篇文章,就意味著系統學習數據結構的開始。本節,我們先來講什麽是數據結構。 技術分享圖片 數據結構,直白地理解,就是研究數據的存儲方式。 我們知道,數據存儲只有一個目的,即為了方便後期對數據的再利用,就如同我們使用數組存儲 {1,2,3,4,5} 是為了後期取得它們的加和值,無緣由的數據存儲行為是對存儲空間的不負責任。
因此,數據在計算機存儲空間的存放方式,決不是胡亂的,這就要求我們選擇一種好的方式來存儲數據,而這也是數據結構的核心內容。   例如,一直以來大家面對的數據存儲,都是類似存儲 1、2、{a,b,c} 這樣的問題,解決方式無疑是用變量或者數組對數據進行存儲,即:
int a=1;
int b=2;
char str[3]={‘a‘,‘b‘,‘c‘};
但是,如果要存儲這樣一組數據:{張亮,張平,張華,張群,張晶,張磊},數據之間具有這樣的關系:張亮是張平、張華和張群的父親,同時張平還是張晶和張磊的父親,數據之間的關系如 1 所示:

技術分享圖片 圖 1 數據及數據之間的關系
對於存儲之間具有復雜關系的數據,如果還是用變量或數組來存儲(比如用數組存儲 {“張亮”,"張平",“張華”,"張群","張晶","張磊"} ) 純數據存儲是沒有問題,但是無法體現數據之間的邏輯關系,後期根本無法使用,顯然不明智。
總結1:針對此類數據,數據結構中提供有專門的結構來存儲這類數據。
例如:導航無疑是出遊旅行的必備神器,在我們程序員眼中,無論是哪款導航軟件,其導航功能的實現都需要大量地圖數據的支持。 很明顯,這些數據絕不是使用變量或數組進行存儲的,那樣對於數據的使用簡直是個悲劇。
總結2:針對此類數據,數據結構提供了圖存儲結構,專門用於存儲這類數據。
通過以上兩個示例可以體會出:         數據結構教會我們的絕不僅僅是如何存儲 1、2、{a,b,c} 這樣簡單的數據,而是解決具有復雜關系的大量數據的存儲問題。 因此,數據結構是什麽?     我認為,數據結構是一門學科,它教會我們“如何存儲具有復雜關系的數據更有助於後期對數據的再利用
”。
 (1)數據結構是學習數據存儲方式的一門學科,那麽,數據存儲方式有哪幾種呢?本節將對數據結構的學習內容做一個簡要的總結。
數據結構大致包含以下幾種存儲結構:
  • 線性表,還可細分為順序表鏈表隊列
  • 結構,包括普通樹,二叉樹,線索二叉樹等;
  • 存儲結構;
下面對各種數據結構做詳細講解。

1,線性表

線性表結構存儲的數據往往是可以依次排列的,就像小朋友手拉手,每位學生的前面和後面都僅有一個小朋友和他拉手,具備這種“一對一”關系的數據就可以使用線性表來存儲。   例如,存儲類似 {1,3,5,7,9} 這樣的數據時,各元素依次排列,每個元素的前面和後邊有且僅有一個元素與之相鄰(除首元素和尾元素),因此可以使用線性表存儲。
線性表並不是一種具體的存儲結構,它包含順序存儲結構和鏈式存儲結構,是順序表和鏈表的統稱。

順序表

順序表,簡單地理解,就是常用的數組,只是換了個名字而已,例如使用順序表存儲 {1,3,5,7,9},如圖 1 所示:

技術分享圖片

圖 1 順序表結構    由於順序表結構的底層實現借助的就是數組,因此對於初學者來說,可以把順序表完全等價為數組,但實則不是這樣。數據結構是研究數據存儲方式的一門學科,它囊括的都是各種存儲結構,而數組只是各種編程語言中的基本數據類型,並不屬於數據結構的範疇。 鏈表
  我們知道,使用順序表(底層實現靠數組)時,需要提前申請一定大小的存儲空間,這塊存儲空間的物理地址是連續的,如圖 1 所示。
鏈表則完全不同,使用鏈表存儲數據時,是隨用隨申請,因此數據的存儲位置是相互分離的,換句話說,數據的存儲位置是隨機的。

  為了給各個數據塊建立“依次排列”的關系,鏈表給各數據塊增設一個指針,每個數據塊的指針都指向下一個數據塊(最後一個數據塊的指針指向 NULL),就如同一個個小學生都伸手去拉住下一個小學生的手,這樣,看似毫無關系的數據塊就建立了“依次排列”的關系,也就形成了鏈表,如圖 2 所示:

技術分享圖片
圖 2 鏈表結構
棧和隊列   棧和隊列隸屬於線性表,是特殊的線性表,因為它們對線性表中元素的進出做了明確的要求。 中的元素只能從線性表的一端進出(另一端封死),且要遵循“先入後出”的原則,即 先進棧的元素後出棧。 技術分享圖片
圖 3 棧結構示意圖   棧結構如圖 3 所示,像一個木桶,棧中含有 3 個元素,分別是 A、B 和 C,從在棧中的狀態可以看出 A 最先進的棧,然後 B 進棧,最後 C 進棧。根據“先進後出”的原則,3 個元素出棧的順序應該是:C 最先出棧,然後 B 出棧,最後才是 A 出棧。

隊列

  隊列中的元素只能從線性表的一端進,從另一端出,且要遵循“先入先出”的特點,即先進隊列的元素也要先出隊列。

技術分享圖片
圖 4 隊列結構示意圖     隊列結構如圖 4 所示,隊列中有 3 個元素,分別是 A、B 和 C,從在隊列中的狀態可以看出是 A 先進隊列,然後 B 進,最後 C 進。根據“先進先出”的原則,3 個元素出隊列的順序應該是 A 最先出隊列,然後 B 出,最後 C 出。

樹存儲結構

  樹存儲結構適合存儲具有“一對多”關系的數據。
技術分享圖片
圖 5 家庭族譜     如圖 5 所示,其中張平只有一個父親,但他卻有兩(多)個孩子,這就是“一對多”的關系,滿足這種關系的數據可以使用樹存儲結構。

圖存儲結構

    圖存儲結構適合存儲具有“多對多”關系的數據。
技術分享圖片
圖 6 圖存儲結構示意圖
  如圖 6 所示,從 V1 可以到達 V2、V3、V4,同樣,從 V2、V3、V4 也可以到達 V1,這就是“多對多”的關系,滿足這種關系的數據可以使用圖存儲結構。

算法時間復雜度和空間復雜度的計算

算法,即解決問題的方法。同一個問題,使用不同的算法,雖然得到的結果相同,但是耗費的時間和資源是不同的。

比如:要擰一個螺母,使用扳手還是鉗子是有區別的,雖然使用鉗子也能擰螺母,但是沒有扳手好用。
    “條條大路通羅馬”,解決問題的算法有多種,這就需要判斷哪個算法“更好”。

算法VS程序

  很多人誤以為程序就是算法,其實不然:

  • 算法是解決某個問題的想法、思路;
  • 程序是在心中有算法的前提下編寫出來的可以運行的代碼。

  例如,要解決依次輸出一維數組中的數據元素的值的問題,首先想到的是使用循環結構( for 或者 while ),在有這個算法的基礎上,開始編寫程序。
所以,算法相當於是程序的雛形。當解決問題時,首先心中要有解決問題的算法,圍繞算法編寫出程序代碼。

有算法一定能解決問題嗎?

  對於一個問題,想出解決的算法,不一定就能解決這個問題。
  例如:

  擰螺 母,扳手相對於鉗子來說更好使(選擇算法的過程),但是在擰的過程(編寫程序的過程)中發現螺母生銹擰不動,這時就需要另想辦法。
為了避免這種情況的發生,要充分全面地思考問題,盡可能地考慮到所有地可能情況,慎重選擇算法(需要在實踐中不斷地積累經驗)

“好”算法的標準

  對於一個問題的算法來說,之所以稱之為算法,首先它必須能夠解決這個問題(稱為準確性)。其次,通過這個算法編寫的程序要求在任何情況下不能崩潰(稱為健壯性)。
如果準確性和健壯性都滿足,接下來,就要考慮最重要的一點:通過算法編寫的程序,運行的效率怎麽樣。

運行效率體現在兩方面:

  • 算法的運行時間。(稱為“時間復雜度”)
  • 運行算法所需的內存空間大小。(稱為“空間復雜度”)

總結:

  好算法的標準就是:在符合算法本身的要求的基礎上,使用算法編寫的程序運行的時間短,運行過程中占用的內存空間少,就可以稱這個算法是“好算法”。

調查表明,人們對於軟件或者 APP 的運行效率有極高的要求,

  例如:對於網頁打開的忍耐極限是 6 秒甚至更短,如果你設計的網頁打開的時間超過 6 秒,多數人會在 4 秒甚至 3 秒的時候毫不猶豫地關掉而去瀏覽其他網頁。在這個大背景下,一個好的“算法”更註重的是時間復雜度,而空間復雜度只要在一個合理的範圍內就可以。

時間復雜度的計算

  計算一個算法的時間復雜度,不可能把所有的算法都編寫出實際的程序出來讓計算機跑,這樣會做很多無用功,效率太低。實際采用的方法是估算算法的時間復雜度。
在學習C語言的時候講過,程序由三種結構構成:順序結構、分支結構和循環結構。順序結構和分支結構中的每段代碼只運行一次;循環結構中的代碼的運行時間要看循環的次數。
由於是估算算法的時間復雜度,相比而言,循環結構對算法的執行時間影響更大。 所以,算法的時間復雜度,主要看算法中使用到的循環結構中代碼循環的次數(稱為“頻度”)。次數越少,算法的時間復雜度越低。 例如:
a) ++x; s=0;  //a 代碼的運行了 1 次
b) for (int i=1; i<=n; i++) { //b 代碼的運行了 n 次 
     ++x;
     s+=x; 
}      
c) for (int i=1; i<=n; i++) { 
        for (int j=1; i<=n; j++) {//c 代碼運行了 n*n 次。   
           ++x;
             s+=x;
 } }                     

時間復雜度的表示

算法的時間復雜度的表示方式為:(註意,是大寫的字母O,不是數字0)

O(頻度) // 這種表示方式稱為大“O”記法

對於上邊的例子而言,a 的時間復雜度為O(1),b 的時間復雜度為O(n),c 的時間復雜度為為O(n2)。 簡化的過程總結為3步:
  1. 去掉運行時間中的所有加法常數。(例如 n2+n+1,直接變為 n2+n)
  2. 只保留最高項。(n2+n 變成 n2
  3. 如果最高項存在但是系數不是1,去掉系數。(n2 系數為 1)
所以,最終a、b和c合並而成的代碼的時間復雜度為O(n2)

常用的時間復雜度的排序

列舉了幾種常見的算法時間復雜度的比較(又小到大)
O(1)常數階 < O(logn)對數階 < O(n)線性階 < O(n2)平方階 < O(n3)(立方階) < O(2n) (指數階)
技術分享圖片


從圖中可見,我們應該盡可能選用多項式階O(nk)的算法,而不希望用指數階的算法。

常見的算法時間復雜度由小到大依次為:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)

一般情況下,對一個問題(或一類算法)只需選擇一種基本操作來討論算法的時間復雜度即可,有時也需要同時考慮幾種基本操作,甚至可以對不同的操作賦予不同的權值,以反映執行不同操作所需的相對時間,這種做法便於綜合比較解決同一問題的兩種完全不同的算法。

(3)求解算法的時間復雜度的具體步驟是:

⑴ 找出算法中的基本語句;

    算法中執行次數最多的那條語句就是基本語句,通常是最內層循環的循環體。

  ⑵ 計算基本語句的執行次數的數量級;

    只需計算基本語句執行次數的數量級,這就意味著只要保證基本語句執行次數的函數中的最高次冪正確即可

    註意:可以忽略所有 低次冪最高次冪的系數。這樣能夠簡化算法分析,並且使註意力集中在最重要的一點上:增長率。

  ⑶ 用大Ο記號表示算法的時間性能。

  將基本語句執行次數的數量級放入大Ο記號中。

情況一:

  如果算法中包含嵌套的循環,則基本語句通常是最內層的循環體,如果算法中包含並列的循環,則將並列循環的時間復雜度相加。例如:

for (i=1; i<=n; i++)  
       x++;  
for (i=1; i<=n; i++)  
     for (j=1; j<=n; j++)  
          x++;  

結果:第一個for循環的時間復雜度為Ο(n),第二個for循環的時間復雜度為Ο(n2),則整個算法的時間復雜度為Ο(n+n2)=Ο(n2)。

    Ο(1)表示基本語句的執行次數是一個常數,一般來說,只要算法中不存在循環語句,其時間復雜度就是Ο(1)。其中Ο(log2n)、Ο(n)、 Ο(nlog2n)、Ο(n2)和Ο(n3)稱為多項式時間而Ο(2n)和Ο(n!)稱為指數時間

    計算機科學家普遍認為前者(即多項式時間復雜度的算法)是有效算法,把這類問題稱為P(Polynomial,多項式)類問題,而把後者(即指數時間復雜度的算法)稱為NP(Non-Deterministic Polynomial, 非確定多項式)問題

一般來說多項式級的復雜度是可以接受的,很多問題都有多項式級的解——也就是說,這樣的問題,對於一個規模是n的輸入,在n^k的時間內得到結果,稱為P問題。有些問題要復雜些,沒有多項式時間的解,但是可以在多項式時間裏驗證某個猜測是不是正確。

  比如問4294967297是不是質數?如果要直接入手的話,那麽要把小於4294967297的平方根的所有素數都拿出來,看看能不能整除。還好歐拉告訴我們,這個數等於641和6700417的乘積,不是素數,很好驗證的,順便麻煩轉告費馬他的猜想不成立。大數分解、Hamilton回路之類的問題,都是可以多項式時間內驗證一個“解”是否正確,這類問題叫做NP問題。

(4)在計算算法時間復雜度時有以下幾個簡單的程序分析法則:

  (1).對於一些簡單的輸入輸出語句或賦值語句,近似認為需要O(1)時間

  (2).對於順序結構,需要依次執行一系列語句所用的時間可采用大O下"求和法則"

  對於復雜算法,可以認為將它分成幾個容易估算的部分分別估算,然後利用求和法則和乘法法則計算整個算法的時間復雜度,

求和法則:是指若算法的2個部分時間復雜度分別為 T1(n)=O(f(n))和 T2(n)=O(g(n)),則 T1(n)+T2(n)=O(max(f(n), g(n))) (相同問題規模時)

特別地,若T1(m)=O(f(m)), T2(n)=O(g(n)),則 T1(m)+T2(n)=O(f(m) + g(n)) (不相同問題規模時)

  (3).對於選擇結構,如if語句,它的主要時間耗費是在執行then字句或else字句所用的時間,需註意的是檢驗條件也需要O(1)時間

  (4).對於循環結構,循環語句的運行時間主要體現在多次叠代中執行循環體以及檢驗循環條件的時間耗費,一般可用大O下"乘法法則"

乘法法則: 是指若算法的2個部分時間復雜度分別為 T1(n)=O(f(n))和 T2(n)=O(g(n)),則 T1*T2=O(f(n)*g(n)) (不相同問題規模時和相同問題規模)

  (5).對於復雜的算法,可以將它分成幾個容易估算的部分,然後利用求和法則和乘法法則技術整個算法的時間復雜度

另外還有以下2個運算法則:

    (1) 若g(n)=O(f(n)),則O(f(n))+ O(g(n))= O(f(n));

     (2) O(Cf(n)) = O(f(n)),其中C是一個正常數

(5)下面分別對幾個常見的時間復雜度進行示例說明:

(1)、O(1)

Temp=i; i=j; j=temp;

以上三條單個語句的頻度均為1,該程序段的執行時間是一個與問題規模n無關的常數。算法的時間復雜度為常數階,記作T(n)=O(1)。

註意:如果算法的執行時間不隨著問題規模n的增加而增長,即使算法中有上千條語句,其執行時間也不過是一個較大的常數。此類算法的時間復雜度是O(1)。

(2)、O(n2)

2.1. 交換i和j的內容

sum=0;                 (一次)  
for(i=1;i<=n;i++)     (n+1次)執行n次後再回來判斷不符合條件的(n+1)項,然後跳出循環繼續執行  
   for(j=1;j<=n;j++) (n2次)  
    sum++;            (n2次)  

解:因為Θ(2n2+n+1)=n2(Θ即:去低階項,去掉常數項,去掉高階項的常參得到),所以T(n)= =O(n2);

2.2.

for (i=1;i<n;i++)  
 {   
     y=y+1;         ①     
     for (j=0;j<=(2*n);j++)      
        x++;         ②    

解: 語句1的頻度是n-1
語句2的頻度是(n-1)*(2n+1)=2n2-n-1
f(n)=2n2-n-1+(n-1)=2n2-2;

Θ(2n2-2)=n2
該程序的時間復雜度T(n)=O(n2).

  一般情況下,對步進循環語句只需考慮循環體中語句的執行次數,忽略該語句中步長加1、終值判別、控制轉移等成分,當有若幹個循環語句時,算法的時間復雜度是由嵌套層數最多的循環語句中最內層語句的頻度f(n)決定的。

(3)、O(n)

a=0;  
  b=1;               ①  
  for (i=1;i<=n;i++) ②  
  {    
     s=a+b;    ③  
     b=a;     ④    
     a=s;     ⑤  
  }  

解: 語句1的頻度:2,
語句2的頻度: n,
語句3的頻度: n-1,
語句4的頻度:n-1,
語句5的頻度:n-1,
T(n)=2+n+3(n-1)=4n-1=O(n).
(4)、O(log2n)

不懂得可以看這個博主(與二分搜索樹有關):https://blog.csdn.net/li396864285/article/details/79820808

i=1;     ①  O(1)
hile (i<=n)  O(n) 
  i=i*2; ②  O(f(n))   則:2^f(n)<=n;f(n)<=log2n 

解: 語句1的頻度是1,
設語句2的頻度是f(n), 則:2^f(n)<=n;f(n)<=log2n
取最大值f(n)=log2n,
T(n)=O(log2n )

(5)、O(n3)

for(i=0;i<n;i++)  
   {    
      for(j=0;j<i;j++)    
      {  
         for(k=0;k<j;k++)  
            x=x+2;    
      }  
   }  

解:當i=m, j=k的時候,內層循環的次數為k當i=m時, j 可以取 0,1,...,m-1 , 所以這裏最內循環共進行了0+1+...+m-1=(m-1)m/2次所以,i從0取到n, 則循環共進行了: 0+(1-1)*1/2+...+(n-1)n/2=n(n+1)(n-1)/6所以時間復雜度為O(n3).

(5)常用的算法的時間復雜度和空間復雜度

技術分享圖片

一個經驗規則:其中c是一個常量,如果一個算法的復雜度為c 、 log2n 、n 、 n*log2n ,那麽這個算法時間效率比較高 ,如果是2n ,3n ,n!,那麽稍微大一些的n就會令這個算法不能動了,居於中間的幾個則差強人意。

算法時間復雜度分析是一個很重要的問題,任何一個程序員都應該熟練掌握其概念和基本方法,而且要善於從數學層面上探尋其本質,才能準確理解其內涵。

拿時間換空間,用空間換時間

算法的時間復雜度和空間復雜度是可以相互轉化的。
比如:
谷歌瀏覽器相比於其他的瀏覽器,運行速度要快。是因為它占用了更多的內存空間,以空間換取了時間。
 算法中,

例如 判斷某個年份是否為閏年時,

(1)如果想以時間換取空間,算法思路就是:當給定一個年份時,判斷該年份是否能被4或者400整除,如果可以,就是閏年。

(2)如果想以空間換時間的話,判斷閏年的思路就是:把所有的年份先判斷出來,存儲在數組中(年份和數組下標對應),如果是閏年,數組值是1,否則是0;當需要判斷某年是否為閏年時,直接看對應的數組值是1還是0,不用計算就可以馬上知道。

例如 當一個算法的空間復雜度為一個常量,即不隨被處理數據量n的大小而改變時,可表示為O(1);

     當一個算法的空間復雜度與以2為底的n的對數成正比時,可表示為0(10g2n);

     當一個算法的空I司復雜度與n成線性比例關系時,可表示為0(n).

   若形參為數組,則只需要為它分配一個存儲由實參傳送來的一個地址指針的空間,即一個機器字長空間;若形參為引用方式,則也只需要為其分配存儲一個地址的空間,用它來存儲對應實參變量的地址,以便由系統自動引用實參變量。

【1】如果算法的執行時間不隨著問題規模n的增加而增長,即使算法中有上千條語句,其執行時間也不過是一個較大的常數。此類算法的時間復雜度是O(1)。
x=91; y=100;
while(y>0) if(x>100) {x=x-10;y--;} else x++;
解答: T(n)=O(1),
這個程序看起來有點嚇人,總共循環運行了1100次,但是我們看到n沒有?
沒。這段程序的運行是和n無關的,
就算它再循環一萬年,我們也不管他,只是一個常數階的函數 【2】當有若幹個循環語句時,算法的時間復雜度是由嵌套層數最多的循環語句中最內層語句的頻度f(n)決定的。
x=1; for(i=1;i<=n;i++) for(j=1;j<=i;j++) for(k=1;k<=j;k++) x++;   
該程序段中頻度最大的語句是(5),內循環的執行次數雖然與問題規模n沒有直接關系,但是卻與外層循環的變量取值有關,而最外層循環的次數直接與n有關,因此可以從內層循環向外層分析語句(5)的執行次數: 則該程序段的時間復雜度為T(n)=O(n3/6+低次項)=O(n3) 【3】算法的時間復雜度不僅僅依賴於問題的規模,還與輸入實例的初始狀態有關。 在數值A[0..n-1]中查找給定值K的算法大致如下:
i=n-1; while(i>=0&&(A[i]!=k)) i--; return i;
此算法中的語句(3)的頻度不僅與問題規模n有關,還與輸入實例中A的各元素取值及K的取值有關: ①若A中沒有與K相等的元素,則語句(3)的頻度f(n)=n; ②若A的最後一個元素等於K,則語句(3)的頻度f(n)是常數0。 (5)時間復雜度評價性能 有兩個算法A1和A2求解同一問題,時間復雜度分別是T1(n)=100n2,T2(n)=5n3。(1)當輸入量n<20時,有T1(n)>T2(n),後者花費的時間較少。(2)隨著問題規模n的增大,兩個算法的時間開銷之比5n3/100n2=n/20亦隨著增大。即當問題規模較大時,算法A1比算法A2要有效地多。它們的漸近時間復雜度O(n2)和O(n3)從宏觀上評價了這兩個算法在時間方面的質量。在算法分析時,往往對算法的時間復雜度和漸近時間復雜度不予區分,而經常是將漸近時間復雜度T(n)=O(f(n))簡稱為時間復雜度,其中的f(n)一般是算法中頻度最大的語句頻度。

數據的邏輯結構和物理結構

(1)數據元素之間的相互聯系方式稱為數據的邏輯結構 。數據的邏輯結構是對數據元素之間邏輯關系的描述,它可以用一個數據元素的集合和定義在此集合上的若幹關系來表示。數據的邏輯結構經常被簡稱為數據結構。

按照數據的邏輯結構來分,有兩種形式:線性結構和非線性結構。線性結構是指 除第一個和最後一個數據元素外,每個數據元素有且只有一個前驅元素和一個後繼元素,而非線性數據結構則會有零個或多個前驅元素和零個或多個後繼元素。

(2)數據元素在計算機中的存儲表示方式稱為數據的存儲結構 ,也稱物理結構。任何需要計算機進行管理和處理的數據元素都必須首先按某種方式存儲在計算機中,數據存儲結構能正確地表示出數據元素間的邏輯關系。

按照數據的存儲結構來分,有兩種類型:順序存儲結構鏈式存儲結構

   順序存儲結構是把數據元素存儲在一塊連續地址空間的內存中,其特點是邏輯上相鄰的數據元素在物理上(即內存存儲位置上)也相鄰,數據間的邏輯關系表現在數據元素的存儲位置關系上。

   鏈式存儲結構的關鍵是使用節點,節點是由數據元素域與指針域組合的一個整體,指針將相互關聯的節點銜接起來。其特點是邏輯上相鄰的元素在物理上不一定相鄰,數據間的邏輯關系表現在節點的銜接關系上。

數據的邏輯結構是從邏輯關系角度觀察數據,它與數據的存儲無關,是獨立於計算機的。而數據的存儲結構是邏輯結構在計算機內存中的實現,它是計算機處理的邏輯。

數據結構與算法的聯系:

程序=算法+數據結構。數據結構是算法實現的基礎,算法總是要依賴於某種數據結構來實現的。往往是在發展一種算法的時候,構建了適合於這種算法的數據結構。 算法的操作對象是數據結構。算法的設計和選擇要同時結合數據結構,簡單地說數據結構的設計就是選擇存儲方式,如確定問題中的信息是用數組存儲還是用普通的變量存儲或其他更加復雜的數據結構。算法設計的實質就是對實際問題要處理的數據選擇一種恰當的存儲結構,並在選定的存儲結構上設計一個好的算法。不同的數據結構的設計將導致差異很大的算法。數據結構是算法設計的基礎。用一個形象的比喻來解釋:開采煤礦過程中,煤礦以各種形式深埋於地下。礦體的結構就像相當於計算機領域的數據結構,而煤就相當於一個個數據元素。開采煤礦然後運輸、加工這些“操作”技術就相當於算法。顯然,如何開采,如何運輸必須考慮到煤礦的存儲(物理)結構,只擁有開采技術而沒有煤礦是沒有任何意義的。算法設計必須考慮到數據結構,算法設計是不可能獨立於數據結構的。 另外,數據結構的設計和選擇需要為算法服務。如果某種數據結構不利於算法實現它將沒有太大的實際意義。知道某種數據結構的典型操作才能設計出好的算法。
總之,算法的設計同時伴有數據結構的設計,兩者都是為最終解決問題服務的。

數據結構與算法的區別:

數據結構關註的是數據的邏輯結構、存儲結構以及基本操作,而算法更多的是關註如何在數據結構的基礎上解決實際問題。算法是編程思想,數據結構則是這些思想的邏輯基礎。

數據結構學習總結(1)數據結構的認識