1. 程式人生 > 實用技巧 >資料結構和演算法概述

資料結構和演算法概述

1 資料結構

1.1 什麼是資料結構?

  • 資料結構是一門研究非數值計算的程式設計問題中的操作物件,以及它們之間的關係和操作等相關問題的學科。
  • 簡而言之,資料結構就是把資料元素按照一定的關係組織起來的集合,用來組織和儲存資料。

1.2 資料結構的分類

1.2.1 概述

  • 傳統上,我們可以把資料結構分為邏輯結構和物理結構兩大類。

1.2.2 邏輯結構分類

  • 邏輯結構是從具體問題中抽象出來的模型,是抽象意義上的結構,按照物件中資料元素之間的相互關係分類,也是我們需要關注和討論的問題。
  • 1️⃣集合結構:集合結構中資料元素除了屬於同一個集合外,它們之間沒有任何其他的關係。

  • 2️⃣線性結構:線性結構中的資料元素之間存在一對一的關係。

  • 3️⃣樹形結構:樹形結構中的資料元素之間存在一對多的關係。

  • 4️⃣圖形結構:圖形結構的資料元素是多對多的關係。

1.2.3 物理結構分類

  • 邏輯結構是在計算機中真正的表達方式稱為物理結構,也可以叫做儲存結構。常見的物理解耦股有順序儲存結構、鏈式儲存結構。

  • 1️⃣順序儲存結構:

    • 把資料元素放到地址連續的儲存單元裡面,其資料間的邏輯關係和物理關係是一致的,比如我們常用的陣列就是順序儲存結構。

    • 順序儲存結構存在一定的弊端,就像生活中排隊時,有人插隊,也有人有特殊情況突然離開,這時候整個結構就處於變化中,此時就需要使用鏈式儲存結構了。
  • 2️⃣鏈式儲存結構:

    • 把資料元素放在任意的儲存單元裡面,這組儲存單元可以是連續的,也可以是不連續的。此時,資料元素之間並不能反映元素間的邏輯關係,因此在鏈式儲存結構中引進了一個指標儲存資料元素的地址,這樣通過地址就可以找到相關聯資料元素的位置。

2 演算法

1.1 概述

  • 演算法是指解題方案的準確而完整的描述,是一系列解決問題的清晰指令,演算法代表著用系統的方法解決問題的策略機制。也就是說,能夠對一定規範的輸入,在有限的時間內獲得所要求的結果。
  • 簡而言之,演算法就是根據一定的條件,對一些資料進行計算,得到需要的結果。

1.2 演算法初體驗

  • 在生活中,我們如果遇到某個問題,常常解決方案不是唯一的。

  • 例如,從西安到北京,如何去?會有不同的解決方案,我們可以坐飛機、可以坐火車、可以坐汽車,甚至可以步行,不同的解決方案帶來的時間成本和經濟成本是不一樣的,比如坐飛機用的時間最少,但是費用最高;步行費用最低,但是時間最長。

  • 例如,在北京二環內買一套四合院,如何付款?也會有不同的解決方案,可以一次性現金付清,也可以通過銀行做按揭。這兩種方案帶來的成本也是不一樣的,一次性付清,雖然當時給的錢多,壓力大,但是沒有利息;按揭雖然當時出的錢少,壓力比較小,但是會有利息,而且30年的總利息幾乎是貸款額度的一倍,需要多付不少錢。

  • 在程式中,我們也可以用不同的演算法解決相同的問題,而不同的演算法的成本是不相同的。總體上,一個優秀的演算法追求以下兩個目標:

    • 1️⃣花最少的時間完成需求。
    • 2️⃣佔用最少的記憶體空間完成需求。
  • 下面我們用一些實際的案例體驗一些演算法。

  • 案例1:計算1到100的和。

package com.sunxiaping;

/**
 * ①定義兩個整型變數
 * ②執行100次加法運算
 * ③列印結果到控制檯
 *
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-04 11:19
 */
public class Init {
    public static void main(String[] args) {
        int sum = 0;
        int n = 100;
        for (int i = 0; i <= n; i++) {
            sum += i;
        }
        System.out.println("sum = " + sum);
    }
}
package com.sunxiaping;

/**
 * ①定義兩個整型變數
 * ②執行一次加法運算,一次乘法運算,一次除法運算,總共3次運算
 * ③列印結果到控制檯
 *
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-04 11:19
 */
public class Init {
    public static void main(String[] args) {
        int sum = 0;
        int n = 100;
        sum = (n + 1) * n / 2;
        System.out.println("sum = " + sum);
    }
}

第二種演算法完成需求,花費的時間更少一些。

  • 案例2:計算10的階乘
package com.sunxiaping;

/**
 * 使用遞迴完成需求,fun方法會執行10次,並且第一次執行未完成,呼叫第二次執行,依次內推,最多的時候,需要在棧記憶體開闢10塊記憶體分別執行10個fun方法
 *
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-04 11:19
 */
public class Init {
    public static void main(String[] args) {
        //測試:計算10的階乘
        long fun = fun(10);
        System.out.println("fun = " + fun);
    }

    /**
     * 計算n的階乘
     *
     * @param n
     * @return
     */
    public static long fun(long n) {
        if (n == 1) {
            return 1;
        }
        return n * fun(n - 1);
    }
}
package com.sunxiaping;

/**
 * 使用for迴圈完成需求,fun2方法只會執行一次,最終,只需要在棧記憶體開闢一塊記憶體執行fun2方法即可
 *
 * @author 許大仙
 * @version 1.0
 * @since 2020-12-04 11:19
 */
public class Init {
    public static void main(String[] args) {
        //測試:計算10的階乘
        long fun = fun2(10);
        System.out.println("fun = " + fun);
    }

    /**
     * 計算n的階乘
     *
     * @param n
     * @return
     */
    public static long fun2(long n) {
        long result = 1;
        for (long i = 1; i <= n; i++) {
            result *= i;
        }
        return result;

    }
}

第二種演算法完成需求,佔用的記憶體空間更小。