數據結構學習筆記系列1
視頻網址: https://www.bilibili.com/video/av18586085
彙總貼鏈接:https://blog.csdn.net/DX5618258/article/details/104085229
1.1.1關於數據組織
例1.如何在書架上擺放圖書
操作1:新書如何插入
操作2:如何查找書
方法1:隨便放
操作1:哪裏有空放哪裏
操作2:累死
方法2:按照書名的拼音字母順序排放
操作2:二分查找(如:從L開始分前後區(類似解方程的二分法))
操作1:新書插入難(其後的每本書都需要後移)
方法3:把書架劃分幾塊區域,每塊區域指定擺放某種類別的書,在每種類別內按照書名的拼音字母順序排放
操作1:新書插入(先確定類別,二分查找,移除空位)
操作2:限定類別,再二分查找
問題:1.空間如何分配 2.類別分多細
總結:解決問題方法的效率和數據的組織方式有關
1.1.2關於空間使用
例2:寫程序實現printN,使得傳入一個正整數N的參數後,能順序打印從1到N的全部正整數。
以下爲兩種輸出程序: 1. 循環輸出 2. 遞歸輸出
#include <iostream>
void PrintN(int N);
//程序入口
int main()
{
int N;
scanf_s("%d" , &N );
PrintN( N );
return 0;
}
//循環輸出
void PrintN(int N)
{
for (int i = 1; i <= N;i++)
{
printf("%d\n",i);
}
}
//遞歸輸出(佔用大量內存後再輸出)
void PrintN(int N)
{
if (N)
{
PrintN(N-1);
printf("%d\n", N);
}
return;
}
問題:當N達到10000量級時(每臺機器的配置和性能可能有所區別,當N足夠大時結果都是一樣的),遞歸輸出程序出現異常,原因是佔用內存過大,程序崩潰
總結:解決問題方法的效率和空間的利用效率有關
注:scanf、gets等語句無法正常使用,按照錯誤列表的提示修改指定位置的scanf和gets等語句,scanf改爲scanf_s,gets改爲gets_s……(而且,scanf在讀取數據時不檢查邊界,可能會造成內存訪問越界的問題,使用scanf_s,會多一個參數來控制讀取的字符數量,這樣確實比使用scanf輸入更加安全。)
1.1.3 關於算法效率
例3:寫程序計算給定多項式在給定點x處的值
f(x)=a_0+a_1 x+⋯+a_(n-1) x^(n-1)+a_n x^n
double f1(int n, double a[], double x)
{
double p = a[0];
for (int i = 1; i <= n;i++) { p += (a[i]*pow(x,i)); }
return p;
}
f(x)=a_0+x(a_1+x(⋯(a_(n-1)+x(a_n ))⋯))
double f2(int n, double a[], double x)
{
double p = a[n];
for (int i = n; i > 0;i--) { p = a[i - 1] + x * p; }
return p;
}
例3的問題具體化:多項式簡化爲係數以所在項索引值相同的多項式,即,
並計算該多項式在點x=1.1處的值f(1.1)。
#include <iostream>
#include <time.h> //clock ()函數需要調用此頭文件
#include <math.h> //在vs中可以不調用此頭文件也可以計算pow ()函數
//clock_t是clock()函數返回的變量類型,兩個變量代表程序運行起止時間
clock_t start, stop;
//記錄被測函數的運行時間,單位是秒
double duration;
//定義多項式最大項數
#define MAXN 10
//定義函數執行次數
#define MAXK 1e7
//測試函數的聲明
double f1(int n, double a[], double x);
double f2(int n, double a[], double x);
int main()
{
/*聲明並初始化係數數組*/
double a[MAXN];
for (int i = 0; i < MAXN; i++)
{
a[i] = (double)i;
}
start = clock();/*開始計時*/
for (int i = 0; i < MAXK; i++)
{
f1(MAXN - 1, a, 1.1);
}
stop = clock(); /*結束計時*/
duration = (((double)(stop - start)) / CLK_TCK) /MAXK;
printf("ticks1 = %f\n",(double)(stop - start));
printf("duration1 = %6.2e\n",duration);
start = clock();/*開始計時*/
for (int i = 0; i < MAXK; i++)
{
f2(MAXN - 1, a, 1.1);
}
stop = clock();/*結束計時*/
duration = (((double)(stop - start)) / CLK_TCK) / MAXK;
printf("ticks2 = %f\n", (double)(stop - start));
printf("duration2 = %6.2e\n", duration);
return 0;
}
double f1(int n, double a[], double x)
{
double p = a[0];
for (int i = 1; i <= n;i++)
{
p += (a[i]*pow(x,i));
}
return p;
}
double f2(int n, double a[], double x)
{
double p = a[n];
for (int i = n; i > 0;i--)
{
p = a[i - 1] + x * p;
}
return p;
}
測試結果如下圖
計算結果表明採用第二種方法計算多項式會使計算時間縮短一個數量級。
注:程序中下劃線部分是爲了使時間足夠大,便於數據準確及數據採集,否則結果如下
結論:解決問題方法的效率和算法的巧妙程度有關
1.1.4 抽象數據類型
問:到底什麼是數據結構
1.數據對象在計算機中的組織方式:
-
1.1 邏輯結構:一對一、線性結構;一對多、樹型結構;多對多、圖型結構;
-
1.2 物理存儲結構
2.數據對象必定與一系列加在其上的操作相關聯,完成這些操作所用的方法就是算法
抽象數據類型(Abstract Data Type)
數據類型:數據對象集;數據集合相關聯的操作集
抽象:描述數據類型的方法不依賴於具體實現。即
1.與存放數據的機器無關;
2.與數據存儲的物理結構無關;
3.與實現操作的算法和編程語言無關;
綜上所述:抽象即只描述數據對象集合相關操作集“是什麼”,不涉及“如何做到”的問題。
簡單地類比就是隻看函數的輸入和輸出,不看這個函數是如何實現的具體過程。
例4:“矩陣”的抽象數據類型定義
類型名稱:矩陣(Matrix)
數據對象集:一個MxN的矩陣A_(M×N)=(a_ij)(i=1,⋯,M;j=1,⋯,N)由MxN個三元組<a,i,j>構成,其中a是矩陣元素的值,i是元素所在的行號,j是元素所在的列號。
操作集:對於任意矩陣A、B、C∈Matrix,以及整數i、j、M、N
Matrix Create(int M ,int N):返回一個MxN的空矩陣;
int GetMaxRow(Matrix A):返回矩陣A的總行數;
int GetMaxCol(Matrix A):返回矩陣A的總行數;
Matrix Add(Matrix A,Matrix B):如果A和B的行、列數一致,則返回矩陣C=A+B,否則返回錯誤標誌;
抽象的地方例如:
矩陣A_(M×N)是二維數組還是一維數組還是十字鏈表並未指明,在此處並不關心其是否是哪種類型;
Matrix Add操作是先按行相加還是先按列相加,用什麼語言來實現這個操作,在此處並不關心。