第一週:預備知識—算法與數據結構
解決問題的策略效率與什麼有關?
數據組織方式
圖書館插入新書和查找書籍,用不同的數據組織方式,對應的操作就會有不同的時間複雜度。
數據組織方式好壞的分析,與它所相關的操作有直接聯繫。
空間利用效率
觀察兩段用於輸出1到N的數字的代碼
其一循環算法:
void PrintN(int N) { int i; for (i = 1; i <= N; i++) { printf("%d\n", i); } return; }
其二遞歸算法:
void PrintN(int N) { if (N) { PrintN(N - 1); printf("%d\n", N); } return; }
第二段代碼在數據過大時由於不斷堆棧,空間爆炸,異常終止。
算法巧妙程度
計算多項式在給定點x處的值,兩段代碼
其一:
f(x)=a0+a1x+⋯+an−1xn−1+anxn double f(int n, double a[], double 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(⋯(an−1+x(an)))) double f(int n, double a[], double x) { int i; double p = a[n]; for (i = n; i > 0; i--) { p = a[i - 1] + x * p; } return p; }
兩段代碼在運行時間上有很大區別,究其原因,將乘法視爲關鍵操作,冪次視作多次乘法,則第一段代碼算法
O(n2) , 第二段代碼O(n) .
測試(比較)算法運行效率小方法
#include<stdio.h>
#include<time.h>
#include<math.h>
#define MAX 100
double poly1(int n, double a[], double x) // 坊間算法
{
double p = 0;
for (int i = 0; i <= n; i++) {
p += a[i] * pow(x, i);
}
return p;
}
double poly2(int n, double a[], double x) // 專業算法
{
double p = a[0];
for (int i = n; i > 0; i--) {
p += a[i - 1] + p * x;
}
return p;
}
int main()
{
double coef[MAX], x = 1.1;
clock_t start, stop;
for (int i = 0; i < MAX; i++) {
coef[i] = i / 3.0;
}
start = clock();
for (int i = 0; i < MAX; i++)
poly1(MAX - 1, coef, x);
stop = clock();
printf("Polynomial Algorithm 1---plain Algorithm\n"
"used ticks: %f\n\n", (double)(stop - start));
start = clock();
for (int i = 0; i < MAX; i++)
poly2(MAX - 1, coef, x);
stop = clock();
printf("Polynomial Algorithm 2---professional Algorithm\n"
"used ticks: %f\n\n", (double)(stop - start));
return 0;
}
數據結構與抽象數據結構
數據結構
- 數據對象在計算機中的組織方式
- 邏輯結構
- 物理存儲結構
- 數據對象與施加於其上的操作相關聯
- 實現操作的就是算法
抽象數據結構
- 數據結構
- 數據對象集
- 與數據對象集相關的操作集
- 抽象
- 與物理存儲方式無關
- 與實現的算法和編程語言無關
只定義了對象集和操作集,不涉及如何實現。如下例:
算法與最大子列和問題
熟悉問題,只敲了代碼,在QuizCode裏有
初識PTA
PTA是數據結構這門課採用的OJ系統。
- 會將各個樣例的特徵標在Wrong Answer的標籤旁邊,便於Debug。
- 函數填空題會將一些部分隱藏起來,因此看上去沒有不代表沒有,需仔細讀題。
最大子列和(課堂算法)代碼
課上講的算法
#include<stdio.h>
#include<stdlib.h> // for malloc
int MaximumSubSum(int Data[], int s, int e); // 尋找最大和
int max(int a, int b, int c);
int MaxCrossing(int Data[], int s, int e); // Conquer 尋找跨越中間元素的最大和
int main()
{
int * Data = NULL, Size = 0;
scanf("%d", &Size);
Data = malloc(sizeof(int) * Size); // 動態分配內存
for (int i = 0; i < Size; i++) {
scanf("%d", &Data[i]);
}
int Max = MaximumSubSum(Data, 0, Size - 1); // 尋找
printf("%d\n", Max);
return 0;
}
int MaximumSubSum(int Data[], int s, int e)
{
if (s == e) { // Base Case 只有一個元素
if (Data[s] <= 0) {
return 0;
}
else {
return Data[s];
}
}
int mid = (s + e) / 2;
int Max1 = MaximumSubSum(Data, s, mid);
int Max2 = MaximumSubSum(Data, mid + 1, e); // Divide, 遞歸求解
int Max3 = MaxCrossing(Data, s, e); // Conquer
return max(Max1, Max2, Max3);
}
int max(int a, int b, int c)
{
int result = a;
if (result < b) {
result = b;
}
if (result < c) {
result = c;
}
return result;
}
int MaxCrossing(int Data[], int s, int e)
{
int mid = (s + e) / 2, maxl = 0, maxr = 0, curr = 0;
for (int i = mid; i >= s; i--) { // 左側最大
curr += Data[i];
if (curr > maxl) {
maxl = curr;
}
}
curr = 0; // initialize
for (int i = mid + 1; i <= e; i++) {// 右側最大
curr += Data[i];
if (curr > maxr) {
maxr = curr;
}
}
return maxl + maxr; // 和爲最大
}
算法
#include<stdio.h>
int main()
{
int Size = 0, max = 0, curr = 0, Data = 0; // O(1) extra space
scanf("%d", &Size);
for (int i = 0; i < Size; i++) {
scanf("%d", &Data);
curr += Data;
if (curr > max) { // refresh max
max = curr;
}
if (curr < 0) { // discard curr
curr = 0;
}
}
printf("%d\n", max);
return 0;
}
最大子列和(課後習題)代碼
#include<stdio.h>
#include<stdlib.h> // for malloc
int main()
{
int Bool = 0, Size = 0, max = 0, curr = 0, curr_s = 0, curr_e = 0, s = 0, e = 0;
int * Data; // O(n) extra space
scanf("%d", &Size);
Data = malloc(sizeof(int) * (Size + 1));
for (int i = 0; i < Size; i++) {
scanf("%d", &Data[i]);
}
curr_s = curr_e = s = e = Data[0];
for (int i = 0; i < Size; i++) {
curr += Data[i];
curr_e = Data[i];
if (curr < 0) {
curr = 0;
curr_s = Data[i + 1];
}
if (curr > max) {
max = curr;
s = curr_s;
e = curr_e;
}
}
if (max == 0) { // 爲0特判
s = Data[0];
e = Data[Size - 1];
for (int i = 0; i < Size; i++) {
if (Data[i] == 0) {
s = e = 0;
break;
}
}
}
printf("%d %d %d\n", max, s, e);
return 0;
}