主頁 >  其他 > 拓撲排序就這么回事

拓撲排序就這么回事

2020-09-17 09:02:15 其他

前言

大家好,這里是《齊姐聊演算法》系列之拓撲排序問題,

Topological sort 又稱 Topological order,這個名字有點迷惑性,因為拓撲排序并不是一個純粹的排序演算法,它只是針對某一類圖,找到一個可以執行的線性順序,

這個演算法聽起來高大上,如今的面試也很愛考,比如當時我在面我司時有整整一輪是基于拓撲排序的設計,

但它其實是一個很好理解的演算法,跟著我的思路,讓你再也不會忘記她,

有向無環圖

剛剛我們提到,拓撲排序只是針對特定的一類圖,那么是針對哪類圖的呢?

答:Directed acyclic graph (DAG),有向無環圖,即:

  1. 這個圖的邊必須是有方向的;
  2. 圖內無環,

那么什么是方向呢?

比如微信好友就是有向的,你加了他好友他可能把你刪了你卻不知道,,,那這個朋友關系就是單向的,,

什么是環?環是和方向有關的,從一個點出發能回到自己,這是環,

所以下圖左邊不是環,右邊是,

那么如果一個圖里有環,比如右圖,想執行 1 就要先執行 3,想執行 3 就要先執行 2,想執行 2 就要先執行 1,這成了個死回圈,無法找到正確的打開方式,所以找不到它的一個拓撲序,

總結:

  • 如果這個圖不是 DAG,那么它是沒有拓撲序的;
  • 如果是 DAG,那么它至少有一個拓撲序;
  • 反之,如果它存在一個拓撲序,那么這個圖必定是 DGA.

所以這是一個充分必要條件

拓撲排序

那么這么一個圖的「拓撲序」是什么意思呢?

我們借用百度百科的這個課程表來說明,

課程代號 課程名稱 先修課程
C1 高等數學
C2 程式設計基礎
C3 離散數學 C1, C2
C4 資料結構 C3, C5
C5 演算法語言 C2
C6 編譯技術 C4, C5
C7 作業系統 C4, C9
C8 普通物理 C1
C9 計算機原理 C8

這里有 9 門課程,有些課程是有先修課程的要求的,就是你要先學了「最右側這一欄要求的這個課」才能再去選「高階」的課程,

那么這個例子中拓撲排序的意思就是:
就是求解一種可行的順序,能夠讓我把所有課都學了,

那怎么做呢?

首先我們可以用來描述它,
圖的兩個要素是頂點和邊
那么在這里:

  • 頂點:每門課
  • 邊:起點的課程是終點的課程的先修課

畫出來長這個樣:

這種圖叫 AOV (Activity On Vertex) 網路,在這種圖里:

  • 頂點:表示活動;
  • 邊:表示活動間的先后關系

所以一個 AOV 網應該是一個 DAG,即有向無環圖,否則某些活動會無法進行,
那么所有活動可以排成一個可行線性序列,這個序列就是拓撲序列

那么這個序列的實際意義是:
按照這個順序,在每個專案開始時,能夠保證它的前驅活動都已完成,從而使整個工程順利進行,

回到我們這個例子中:

  1. 我們一眼可以看出來要先學 C1, C2,因為這兩門課沒有任何要求嘛,大一的時候就學唄;

  2. 大二就可以學第二行的 C3, C5, C8 了,因為這三門課的先修課程就是 C1, C2,我們都學完了;

  3. 大三可以學第三行的 C4, C9;

  4. 最后一年選剩下的 C6, C7,

這樣,我們就把所有課程學完了,也就得到了這個圖的一個拓撲排序

注意,有時候拓撲序并不是唯一的,比如在這個例子中,先學 C1 再學 C2,和先 C2 后 C1 都行,都是這個圖的正確的拓撲序,但這是兩個順序了,

所以面試的時候要問下面試官,是要求解任意解,還是列出所有解,

我們總結一下,

在這個圖里的表示的是一種依賴關系,如果要修下一門課,就要先把前一門課修了,

這和打游戲里一樣一樣的嘛,要拿到一個道具,就要先做 A 任務,再完成 B 任務,最終終于能到達目的地了,

演算法詳解

在上面的圖里,大家很容易就看出來了它的拓撲序,但當工程越來越龐大時,依賴關系也會變得錯綜復雜,那就需要用一種系統性的方式方法來求解了,

那么我們回想一下剛剛自己找拓撲序的程序,為什么我們先看上了 C1, C2?

因為它們沒有依賴別人啊,
也就是它的入度為 0.

入度:頂點的入度是指「指向該頂點的邊」的數量;
出度:頂點的出度是指該頂點指向其他點的邊的數量,

所以我們先執行入度為 0 的那些點,
那也就是要記錄每個頂點的入度,
因為只有當它的 入度 = 0 的時候,我們才能執行它,

在剛才的例子里,最開始 C1, C2 的入度就是 0,所以我們可以先執行這兩個,

那在這個演算法里第一步就是得到每個頂點的入度,

Step0: 預處理得到每個點的入度

我們可以用一個 HashMap 來存放這個資訊,或者用一個陣列會更精巧,

在文中為了方便展示,我就用表格了:

C1 C2 C3 C4 C5 C6 C7 C8 C9
入度 0 0 2 2 1 2 2 1 1

Step1

拿到了這個之后,就可以執行入度為 0 的這些點了,也就是 C1, C2.

那我們把可以被執行的這些點,放入一個待執行的容器里,這樣之后我們一個個的從這個容器里取頂點就好了,

至于這個容器究竟選哪種資料結構,這取決于我們需要做哪些操作,再看哪種資料結構可以為之服務,

那么首先可以把[C1, C2]放入容器中,

然后想想我們需要哪些操作吧!

我們最常做的操作無非就是把點放進來把點拿出去執行了,也就是需要一個 offerpoll 操作比較高效的資料結構,那么 queue 就夠用了,

(其他的也行,放進來這個容器里的頂點的地位都是一樣的,都是可以執行的,和進來的順序無關,但何必非得給自己找麻煩呢?一個常規順序的簡簡單單的 queue 就夠用了,)

然后就需要把某些點拿出去執行了,

【劃重點】當我們把 C1 拿出來執行,那這意味這什么?

答:意味著「以 C1 為頂點」的「指向其他點」的「邊」都消失了,也就是 C1 的出度變成了 0.

如下圖,也就是這兩條邊可以消失了,

step1

那么此時我們就可以更新 C1 所指向的那些點也就是 C3 和 C8入度 了,更新后的陣列如下:

C3 C4 C5 C6 C7 C8 C9
入度 1 2 1 2 2 0 1

那我們這里看到很關鍵的一步,C8 的入度變成了 0!

也就意味著 C8 此時沒有了任何依賴,可以放到我們的 queue 里等待執行了,

此時我們的 queue 里就是:[C2, C8].

Step2

下一個我們再執行 C2,

Step2

那么 C2 所指向的 C3, C5入度-1

更新表格:

C3 C4 C5 C6 C7 C9
入度 0 2 0 2 2 1

也就是 C3 和 C5 都沒有了任何束縛,可以放進 queue 里執行了,

queue 此時變成:[C8, C3, C5]

Step3

那么下一步我們執行 C8,

Step3

相應的 C8 所指的 C9 的入度-1.
更新表格:

C4 C6 C7 C9
入度 2 2 2 0

那么 C9 沒有了任何要求,可以放進 queue 里執行了,

queue 此時變成:[C3, C5, C9]

Step4

接下來執行 C3,

Step4

相應的 C3 所指的 C4 的入度-1.
更新表格:

C4 C6 C7
入度 1 2 2

但是 C4 的入度并沒有變成 0,所以這一步沒有任何點可以加入 queue.

queue 此時變成 [C5, C9]

Step5

再執行 C5,

Step5

那么 C5 所指的 C4 和 C6 的入度- 1.
更新表格:

C4 C6 C7
入度 0 1 2

這里 C4 的依賴全都消失啦,那么可以把 C4 放進 queue 里了:

queue = [C9, C4]

Step6

然后執行 C9,

Step6

那么 C9 所指的 C7 的入度- 1.

C6 C7
入度 1 1

這里 C7 的入度并不為 0,還不能加入 queue,

此時 queue = [C4]

Step7

接著執行 C4,

Step7

所以 C4 所指向的 C6 和 C7 的入度-1,
更新表格:

C6 C7
入度 0 0

C6 和 C7 的入度都變成 0 啦!!把它們放入 queue,繼續執行到直到 queue 為空即可,

總結

好了,那我們梳理一下這個演算法:

資料結構
這里我們的入度表格可以用 map 來存放,關于 map 還有不清楚的同學可以看之前我寫的 HashMap 的文章哦~

Map: <key = Vertex, value = https://www.cnblogs.com/nycsde/p/入度>

但實際代碼中,我們用一個 int array 來存盤也就夠了,graph node 可以用陣列的 index 來表示,value 就用陣列里的數值來表示,這樣比 Map 更精巧,

然后用了一個普通的 queue,用來存放可以被執行的那些 node.

程序
我們把入度為 0 的那些頂點放入 queue 中,然后通過每次執行 queue 中的頂點,就可以讓依賴這個被執行的頂點的那些點的 入度-1,如果有頂點的入度變成了 0,就可以放入 queue 了,直到 queue 為空,

細節
這里有幾點實作上的細節:

當我們 check 是否有新的頂點的 入度 == 0 時,沒必要過一遍整個 map 或者陣列,只需要 check 剛剛改動過的就好了,

另一個是如果題目沒有給這個圖是 DAG 的條件的話,那么有可能是不存在可行解的,那怎么判斷呢?很簡單的一個方法就是比較一下最后結果中的頂點的個數和圖中所有頂點的個數是否相等,或者加個計數器,如果不相等,說明就不存在有效解,所以這個演算法也可以用來判斷一個圖是不是有向無環圖

很多題目給的條件可能是給這個圖的 edge list,也是表示圖的一種常用的方式,那么給的這個 list 就是表示圖中的,這里要注意審題哦,看清楚是誰 depends on 誰,其實圖的題一般都不會直接給你這個圖,而是給一個場景,需要你把它變回一個圖,

時間復雜度

注意 ??:對于圖的時間復雜度分析一定是兩個引數,面試的時候很多同學張口就是 O(n)...

對于有 v 個頂點和 e 條邊的圖來說,

第一步,預處理得到 map 或者 array,需要過一遍所有的邊才行,所以是 O(e);

第二步,把 入度 == 0 的點入隊出隊的操作是 O(v),如果是一個 DAG,那所有的點都需要入隊出隊一次;

第三步,每次執行一個頂點的時候,要把它指向的那條邊消除了,這個總共執行 e 次;

總:O(v + e)

空間復雜度

用了一個陣列來存所有點的 indegree,之后的 queue 也是最多把所有的點放進去,所以是 O(v).

代碼

關于這課程排序的問題,Leetcode 上有兩道題,一道是 207,問你能否完成所有課程,也就是問拓撲排序是否存在;另一道是 210 題,是讓你回傳任意一個拓撲順序,如果不能完成,那就回傳一個空 array,

這里我們以 210 這道題來寫,更完整也更常考一些,

Leetcode210

這里給的 input 就是我們剛剛說到的 edge list.

Example 1.

Input: 2, [[1,0]]
Output: [0,1]
Explanation: 這里一共 2 門課,1 的先修課程是 0. 所以正確的選課順序是[0, 1].

Example 2.

Input: 4, [[1,0],[2,0],[3,1],[3,2]]
Output: [0,1,2,3] or [0,2,1,3]
Explanation:這里這個例子畫出來如下圖

Example 3.

Input: 2, [[1,0],[0,1]]
Output: null
Explanation: 這課沒法上了

class Solution {
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        int[] res = new int[numCourses];
        int[] indegree = new int[numCourses];

        // get the indegree for each course
        for(int[] pre : prerequisites) {
            indegree[pre[0]] ++;
        }

        // put courses with indegree == 0 to queue
        Queue<Integer> queue = new ArrayDeque<>();
        for(int i = 0; i < numCourses; i++) {
            if(indegree[i] == 0) {
                queue.offer(i);
            }
        }

        // execute the course
        int i = 0;
        while(!queue.isEmpty()) {
            Integer curr = queue.poll();
            res[i++] = curr;

            // remove the pre = curr
            for(int[] pre : prerequisites) {
                if(pre[1] == curr) {
                    indegree[pre[0]] --;
                    if(indegree[pre[0]] == 0) {
                        queue.offer(pre[0]);
                    }
                }
            }
        }

        return i == numCourses ? res : new int[]{};
    }
}

另外,拓撲排序還可以用 DFS - 深度優先搜索 來實作,限于篇幅就不在這里展開了,大家可以參考GeeksforGeeks的這個資料,

實際應用

我們上文已經提到了它的一個 use case,就是選課系統,這也是最常考的題目,

而拓撲排序最重要的應用就是關鍵路徑問題,這個問題對應的是 AOE (Activity on Edge) 網路,

AOE 網路:頂點表示事件,邊表示活動,邊上的權重來表示活動所需要的時間,
AOV 網路:頂點表示活動,邊表示活動之間的依賴關系,

在 AOE 網中,從起點到終點具有最大長度的路徑稱為關鍵路徑,在關鍵路徑上的活動稱為關鍵活動,AOE 網路一般用來分析一個大專案的工序,分析至少需要花多少時間完成,以及每個活動能有多少機動時間,

具體是怎么應用分析的,大家可以參考這個視頻 的 14 分 46 秒,這個例子還是講的很好的,

其實對于任何一個任務之間有依賴關系的圖,都是適用的,

比如 pom 依賴引入 jar 包時,大家有沒有想過它是怎么導進來一些你并沒有直接引入的 jar 包的?比如你并沒有引入 aop 的 jar 包,但它自動出現了,這就是因為你匯入的一些包是依賴于 aop 這個 jar 包的,那么 maven 就自動幫你匯入了,

其他的實際應用,比如說:

  1. 語音識別系統的預處理;
  2. 管理目標檔案之間的依賴關系,就像我剛剛說的 jar 包匯入;
  3. 深度學習中的網路結構處理,

如有其他補充,歡迎大家在評論區不吝賜教,

以上就是本文的全部內容了,拓撲排序是非常重要也是非常愛考的一類演算法,面試大廠前一定要熟練掌握,

如果你喜歡這篇文章,記得給我點贊留言哦~你們的支持和認可,就是我創作的最大動力,我們下篇文章見!

我是小齊,紐約程式媛,終生學習者,每天晚上 9 點,云自習室里不見不散!

更多干貨文章見我的 Github: https://github.com/xiaoqi6666/NYCSDE

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/64369.html

標籤:其他

上一篇:windows下cocos2dx影片加載問題

下一篇:請問環境配置好,還是找不到cocos命令

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more