1. 程式人生 > >《資料結構與演算法分析》學習筆記-第一章-引論

《資料結構與演算法分析》學習筆記-第一章-引論

自述

自從工作之後,就沒有再寫部落格了,一方面是因為自己初入職場還不能很好的適應職場生活。另一方面也是對前途有些不知所措。現在工作已經快三年了,我慢慢找到了自己的節奏,也許還是有很多不成熟的地方,但是我已經想開啦。做自己真正喜歡的事就好了,遵循自己的內心。在職場的這些年我寫了很多筆記,但是沒有時間整理出來,後面慢慢都會發表出來分享給大家。感覺自己在技術上還是有很多不足,有很多基礎的東西掌握的還是不好呀。所以想踏踏實實的重新學習這些基本知識。包括C語言基礎、資料結構與演算法、作業系統。還希望能更進一步,掌握python、java。學習並整理設計模式、網路、檔案系統、記憶體管理、多執行緒開發等等。請大家敬請期待吧。好了,話不多說。
我,CrazyCatJack又回來啦!

1.1 本書討論的內容

  • 一個可以執行的程式並不夠,如果在巨大的資料集執行,執行時間就變成了相當重要的問題。
  • 學習如何估計程式的執行時間,尤其是在未編碼的情況下預估兩個演算法的執行時間。
  • 學習徹底改程序序速度和確定程式瓶頸的方法,這些方法使我們能夠找到需要大力優化的程式碼段

書上上來就提出了一個演算法問題,並提出了兩個解決方案,我實現了具體的程式碼,大家可以嘗試將這兩個檔案編譯後,檢視列印瞭解具體的執行過程。還可以在linux命令列下使用time ./a.out 命令檢視兩個程式的執行時間,進行比較。我將程式碼上傳到了github上。https://github.com/CrazyCatJack/structureAlgorithm

設有一組N個數而要確定其中第K個最大的數。兩種方法實現如下:

  • 法1:將N個數讀進一個數組,再通過氣泡排序進行遞減排序,最後返回k位置上的元素
// SPDX-License-Identifier: GPL-2.0-only
/*
 * sort1.c
 *
 * Copyright (C) 2020 xuri.All rights reserved.
 */
 
#include <stdio.h>
#define ARRAY_SIZE 1000
#define MAXKNUM 500

int sortK(int *array, int arraySize, int MaxKnum)
{
    if (array == NULL || arraySize <= 0 || MaxKnum <= 0) {
        return -1;
    }

    int subscript, sortTimes;
    for (sortTimes = 0; sortTimes < arraySize - 1; sortTimes++) {
        for (subscript = 1; subscript < arraySize - sortTimes; subscript++) {
            if (array[subscript] > array[subscript - 1]) {
                int temp;
                temp = array[subscript];
                array[subscript] = array[subscript - 1];
                array[subscript - 1] = temp;
            }
        }
#if 0
        printf("NO %d sort:", sortTimes); 
        int prtCnt;
        for (prtCnt = 0; prtCnt < arraySize; prtCnt++) {
            printf("%d ", array[prtCnt]);
        }
        printf("\n"); 
#endif
    }

    return array[MaxKnum - 1]; 
}

void main()
{
    int array[ARRAY_SIZE];
    int assignCnt;
    for (assignCnt = 0; assignCnt < ARRAY_SIZE; assignCnt++) {
        array[assignCnt] = assignCnt;
    }
    int K = sortK(array, ARRAY_SIZE, MAXKNUM);
    printf("K = %d\n", K);  
}
  • 法2:可以先把前K個元素讀入陣列並以遞減的順序進行排序。再將剩下的元素逐個讀入,用新元素與當前陣列中第K個元素進行比較,如果它小於則忽略,如果它大於,則將它放到陣列中正確的位置上,同時擠出一個元素。當演算法終止,第k個元素就是正確答案
// SPDX-License-Identifier: GPL-2.0-only
/*
 * sort2.c
 *
 * Copyright (C) 2020 xuri.All rights reserved.
 */
 
#include <stdio.h>
#define ARRAY_SIZE 1000
#define MAXKNUM 500

void MaoPaoSort(int *localArray, int MaxKnum)
{
    int subscript, sortTimes;
    for (sortTimes = 0; sortTimes < MaxKnum - 1; sortTimes++) {
        for (subscript = 1; subscript < MaxKnum - sortTimes; subscript++) {
            if (localArray[subscript] > localArray[subscript - 1]) {
                int temp;
                temp = localArray[subscript];
                localArray[subscript] = localArray[subscript - 1];
                localArray[subscript - 1] = temp;
            }
        }
#if 0
        printf("NO %d sort:", sortTimes); 
        int prtCnt;
        for (prtCnt = 0; prtCnt < MaxKnum; prtCnt++) {
            printf("%d ", localArray[prtCnt]);
        }
        printf("\n"); 
#endif
    }
}

int sortK(int *array, int arraySize, int MaxKnum)
{
    if (array == NULL || arraySize <= 0 || MaxKnum <= 0) {
        return -1;
    }

    // assign MaxKnum number in localArray
    int localArray[MaxKnum];
    int assignCnt;
    for (assignCnt = 0; assignCnt < MaxKnum; assignCnt++) {
        localArray[assignCnt] = array[assignCnt];
    }
    
    // sort localArray
    MaoPaoSort(localArray, MaxKnum);

    // get remain number in array add to in localArray for sort
    for (assignCnt = MaxKnum; assignCnt < arraySize; assignCnt++) {
        if (array[assignCnt] > localArray[MaxKnum - 1]) {
            int temp = 0;
            temp = array[assignCnt];
            array[assignCnt] = localArray[MaxKnum - 1];
            localArray[MaxKnum - 1] = temp;
            MaoPaoSort(localArray, MaxKnum);
        }
    }

    return localArray[MaxKnum - 1]; 
}

void main()
{
    int array[ARRAY_SIZE];
    int assignCnt;
    for (assignCnt = 0; assignCnt < ARRAY_SIZE; assignCnt++) {
        array[assignCnt] = assignCnt;
    }
    int K = sortK(array, ARRAY_SIZE, MAXKNUM);
    printf("K = %d\n", K);  
}

1.2 數學知識複習

因為數學格式很難打出來,所以乾脆手寫啦,這裡委屈大家看我的醜字了-_-||
好記性不如爛筆頭,CCJ也建議大家親自演算一下,自己演算出來的才算是自己的東西。





1.2.5 證明方法

1)歸納法

  1. 基準情形:確定某些小值得正確性
  2. 歸納假設:假設定理對於小於有限數k的所有情況成立,用這個定理證明k+1也是成立的

    2) 反證法

    通過假設定理不成立,然後證明該假設導致某個已知的性質而不成立,從而說明原假設是錯誤的




1.3 遞迴簡論

  1. 當一個函式用它自己來定義時,就稱為是遞迴的。不是所有的數學遞迴函式都能有效的(或正確的)由C的遞迴模擬來實現。
  2. C中的遞迴函式==若無基準情況,也是毫無意義的==
  3. 跟蹤掛起的函式呼叫(即這些呼叫已經開始但是正等待著遞迴呼叫來完成)以及它們中變數的記錄工作都是由計算機自動完成的。遞迴呼叫將==反覆進行直到基準情形出現==
  4. 遞迴組成
    • 基準情形:不用遞迴就能求解的情形
    • 不斷推進:對於需要遞迴求解的情形,遞迴呼叫必須總能朝著產生基準情形的方向推進
    • 設計法則:假設所有的遞迴呼叫都能執行。不必追蹤所有的遞迴呼叫,很困難且沒必要。使用遞迴能簡化演算法設計並設計出簡潔的程式碼
    • 合成效益法則: 在求解一個問題的同一例項時,切勿在不同的遞迴呼叫中做重複性的工作。例如計算斐波那契數列用遞迴就不是很好的選擇
      ```
      // 本書例程

      include <stdio.h>

int F(int x)
{
if (0 == x) {
return 0;
} else (0 > x) {
return (2 * F(x-1) + x * x);
}
}

void main()
{
printf("F(1)=%d, F(2)=%d, F(3)=%d\n", F(1), F(2), F(3));
}

列印輸出數

// 本書例程

include <stdio.h>

int printDigit(int x)
{
if (x >= 10) {
printDigit((x / 10));
}
printf("%d", (x % 10));
}

void main()
{
int a = 123456789;
printDigit(a);
}
```
***
敬告:

本文原創,歡迎大家學習轉載^_^

==轉載請在顯著位置註明:==

博主ID:CrazyCatJack

原始博文連結地址:https://www.cnblogs.com/CrazyCatJack/p/12545591.html
***

第一章到此結束,接下來會進行課後習題的講解。希望能給正在學習資料結構與演算法的朋友帶來幫助。我們一起來構築一個更好的世界!
覺得好的話請幫忙點個推薦,謝謝大家的支援!嘿嘿~

CrazyCatJack