《資料結構》第一講基本概念 1.1什麼是資料結構 1.1.1關於資料群組織-例:圖書擺放
”資料結構是資料對象,以及存在於該對象的執行個體和組成執行個體的資料元素之間的各種聯絡。這些聯絡可以通過定義相應的函數來給出。“ Sartaj Sahni《資料結構、演算法與應用》
”資料結構是ADT(抽象資料類型Abstract Data Type)的物理實現“ Clifford A.Shaffer 《資料結構與演算法分析》
”資料結構(data structure)是電腦中儲存、組織資料的方式。通常情況下,精心選擇的資料結構可以帶來最優效率的演算法。“ 中文維基百科
例1:如何在書架上擺放圖書。
資料如何組織和規模有關係。
圖書的擺放要使得兩個操作方便實現,操作1:新書怎麼插入。操作2:怎麼找到某本指定的書。
方法1:隨便放。操作1:哪裡有空放哪,一步到位。操作2:難以實現。
方法2:按照書名的拼音字母順序排放。操作1:難以實現,比如新進一本《阿Q正傳》,則要將之後的書一本一本往後錯位,直到前面留出空當為止。操作2:二分尋找。
方法3:把書架劃分成幾塊地區,每塊地區指定擺放某種類別的書,每種類別內,按照書名的字母拼音順序排放。操作1:先定類別,二分尋找確定位置,移出空位。操作2:先定類別,再二分尋找。
基於方法3,問題:空間如何分配。類別應該分多細。
上述例子說明,解決問題方法的效率,跟資料的組織方式有關。 討論1.1 對中等規模、大規模的圖書擺放,你有什麼更好的建議。
答:先分大類,大類可以再細分小類,基於合適的數量時,再利用拼音字母順序擺放。也可以利用電腦建立索引目錄,對所有書按類別,按出版時間,按作者等以不同方式進行編號,可以通過不同的檢索條件,快速尋找到圖書。 1.1.2關於空間使用-例:PrintN函數實現
例2:寫程式實現一個函數PrintN,使得傳入一個正整數為N的參數後,能順序列印從1到N的全部正整數
迴圈實現:
[cpp] view plain copy void PrintN(int N) { for(int i = 1;i < N;i++) printf("%d\n",i); return; } 遞迴實現:
[cpp] view plain copy void PrintN(int N) { if(N) { PrintN(N - 1); printf("%d\n",N); } return; } 遞迴實現沒有用到臨時變數i,看上去更簡潔,輸入比較小的正整數時,兩個版本的結果也類似,但在我的電腦上,當N大於等於65081時,迴圈實現還是可以正常運行,而遞迴實現沒有列印出任何數,如下圖所示。
因為遞迴程式對空間佔用很大,上述程式就是因為遞迴程式用完了能用的空間,非正常終止了。
上述例子說明,解決問題方法的效率,跟空間的利用效率有關。
1.1.3關於演算法效率-例:計算多項式值 例3:寫程式計算給定多項式在給定點x處的值
多項式:f(x) = a0 + a1*x + a2*x^2 + ……+ an-1*x^(n-1) + an*x^n
最直接的演算法:
[cpp] view plain copy double f1(int n,double a[],double x) //n為階數,係數放在數組a中,x為要計算的點 { int i; double p = a[0]; for(i = 1;i <= n;i++) p += (a[i] * pow(x,i)); return p; } 多項式另一種寫法( 秦九韶演算法):f(X) = a0 + x*(a1 + x*(…+x*(an-1 + x*(an))…)
[cpp] view plain copy double f2(int n,double a[],double x) //n為階數,係數放在數組a中,x為要計算的點 { int i; double p = a[n]; for(int i = n;i > 0;i--) p = a[i-1] + x * p; return p; }
我們開始比較兩種函數的已耗用時間:
C語言提供了clock():捕捉從程式開始運行到clock()被調用時所耗費的時間。這個時間單位是clock tick,即”時鐘打點“。常數CLK_TCK:機器時鐘每秒所走的時鐘打點數。