聽課筆記---數據結構(浙江大學)MOOC---第一週

第一週:預備知識—算法與數據結構

解決問題的策略效率與什麼有關?

  1. 數據組織方式

    圖書館插入新書和查找書籍,用不同的數據組織方式,對應的操作就會有不同的時間複雜度。

    數據組織方式好壞的分析,與它所相關的操作有直接聯繫。

  2. 空間利用效率

    觀察兩段用於輸出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;
    }

    第二段代碼在數據過大時由於不斷堆棧,空間爆炸,異常終止。

  3. 算法巧妙程度

    計算多項式在給定點x處的值,兩段代碼

    其一:f(x)=a0+a1x++an1xn1+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((an1+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;
}

數據結構與抽象數據結構

數據結構

  • 數據對象在計算機中的組織方式
    • 邏輯結構
    • 物理存儲結構
  • 數據對象與施加於其上的操作相關聯
  • 實現操作的就是算法

抽象數據結構

  • 數據結構
    • 數據對象集
    • 與數據對象集相關的操作集
  • 抽象
    • 與物理存儲方式無關
    • 與實現的算法和編程語言無關

只定義了對象集和操作集,不涉及如何實現。如下例:1

算法與最大子列和問題

熟悉問題,只敲了代碼,在QuizCode裏有

初識PTA

PTA是數據結構這門課採用的OJ系統。

  • 會將各個樣例的特徵標在Wrong Answer的標籤旁邊,便於Debug。
  • 函數填空題會將一些部分隱藏起來,因此看上去沒有不代表沒有,需仔細讀題。

最大子列和(課堂算法)代碼

課上講的算法O(nlogn) 實現

#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;                 // 和爲最大
}

算法O(n) 實現

#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;
}

最大子列和(課後習題)代碼

O(n) 實現

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章