unity算法面试_Unity面试准备
前言
為Unity面試而準備一些問題,如果有什么說的不對的,歡迎指正
語言機制類
1、GC機制
在C/C++中程序員要自己負責系統(tǒng)的內(nèi)存管理,而C#采用Garbage Collection自動回收內(nèi)存,
當Java虛擬機(VM)或.NETCLR發(fā)覺內(nèi)存資源緊張的時候,就會自動地去清理無用對象(沒有被引用到的對象)所占用的內(nèi)存空間,
查找沒有被引用的對象有一系列的算法,
Lua語言的GC機制采用是Mark and Sweep算法。
2、協(xié)程線程進程
進程一個具有獨立功能的程序在一個數(shù)據(jù)集合上的一次動態(tài)執(zhí)行過程(程序是靜態(tài)的代碼,進程是動態(tài)執(zhí)行的過程)
線程:進程是分配資源的基本單位,而線程則是系統(tǒng)調(diào)度的基本單位。
一個進程內(nèi)部的線程可以共享該進程的所分配到的資源。線程的創(chuàng)建與撤消,線程之間的切換所占用的資源比進程要少很多。
總的來說就是為了更進一步提高系統(tǒng)的并發(fā)性,提高CPU的利用率。
協(xié)程:是一種比線程更加輕量級的存在,協(xié)程調(diào)度不是被操作系統(tǒng)內(nèi)核所管理,而完全是由程序所控制(也就是在用戶態(tài)執(zhí)行),你可以隨時把它掛起。
一個線程里可以有多個協(xié)程。協(xié)程的切換幾乎沒有操作系統(tǒng)的內(nèi)核開銷,不會像線程切換那樣消耗資源(線程切換要改Context)。
協(xié)程的一大好處就是可以避免數(shù)據(jù)訪問沖突的問題因為它的粒度相對多線程的大很多,所以往往很少出現(xiàn)沖突現(xiàn)象。協(xié)程寫入死循環(huán)會將線程卡死。
(配圖有些問題,yield return null是讓協(xié)程在下一個yield null執(zhí)行,如果在update前啟動了協(xié)程,那么在update后的yield的null是會執(zhí)行的)
3、裝箱與拆箱
值類型變量封裝object類型變量或者對應的object將這個值類型從棧區(qū)copy到堆區(qū)產(chǎn)生一個引用類型叫做裝箱;
把這個堆上的obj轉(zhuǎn)成值類型,從堆上往棧上搬東西叫做拆箱,裝箱和拆箱會損失一定性能。
按理說C#被設計成一種完全面向?qū)ο蟮恼Z言。因此,包括數(shù)字、字符、日期、布爾值等等在內(nèi)的一切,都是對象。似乎只需要一種方式來對待這些對象就可以了。
但是C#必須為性能而妥協(xié),我們知道,對于CPU來說,處理一個完整的對象,需要很多的指令,
對于內(nèi)存來說,又需要很多的內(nèi)存。如果連整數(shù)都是對象,那么性能自然很低。
C#于是使用了一種機制,使得這些基本類型在一般的編程中被當作非對象的簡單類型處理,
在另一些場合(比如需要多個腳本引用同一個對象)又允許它們被視作是一個對象。(摘自評論)
4、值類型和引用類型的區(qū)別
值類型的數(shù)據(jù)存儲在內(nèi)存的棧中,引用類型的數(shù)據(jù)存儲在內(nèi)存的堆中
值類型存取速度快,引用類型存取速度慢
類型表示實際數(shù)據(jù)放在棧中;引用類型表示指向存儲在內(nèi)存堆中的數(shù)據(jù)的指針或引用,在棧中存放實際數(shù)據(jù)的地址,堆上存放實際數(shù)據(jù)
棧的內(nèi)存分配是自動釋放;而堆在.NET中會有GC來釋放
值類型繼承自System.ValueType,引用類型繼承自System.Object
5、lua如何實現(xiàn)面向?qū)ο?#xff1f;lua的元表?
由于暫時沒怎么學lua,TODOOOOOOOOOO
6、閉包
閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)
閉包這個詞本身指的是一種函數(shù)。而創(chuàng)建這種特殊函數(shù)的一種常見方式是在一個函數(shù)中創(chuàng)建另一個函數(shù)。
閉包中引用的變量實際上就是把原來聲明在主體中的變量轉(zhuǎn)移到用匿名密封類或者結(jié)構(gòu)體里,
最終在主體中訪問的變量就是生成的匿名類中對象。來自博客
C#里可以在函數(shù)里放一個委托或者匿名函數(shù)引用局部變量。
7、反射
程序一般都是操作數(shù)據(jù),但有時程序也操作程序和程序類型本身的信息,這種信息稱為元數(shù)據(jù),意義為數(shù)據(jù)的數(shù)據(jù)。
反射指程序可以訪問、檢測和修改它本身狀態(tài)或行為的一種能力。
程序集包含模塊,而模塊包含類型,類型又包含成員。反射則提供了封裝程序集、模塊和類型的對象。
您可以使用反射動態(tài)地創(chuàng)建類型的實例,將類型綁定到現(xiàn)有對象,或從現(xiàn)有對象中獲取類型。然后,可以調(diào)用類型的方法或訪問其字段和屬性。它允許程序創(chuàng)建和控制任何類的對象,無需知道目標類,沒有類型依賴,而且還能訪問對象的各個成員。
Unity中的GetComponent的方法都是使用了反射機制,獲取當前GameObject下動態(tài)運行的組件,然后對其進行操作。大部分情況我們使用的是被封裝好的反射。
Unity常用組件類
1、Canvas的三種渲染模式
Screen Space - Overlay:UI元素直接覆蓋在任何攝像機的上方。
Screen Space - Camera:需要指定一個攝像機,UI組件可以控制和攝像機的距離,可以和場景里的物體做一些遮擋之類的交互。
World Space :畫布相對于世界空間,和場景物體一樣有遮擋關系,可以旋轉(zhuǎn),3d UI制作,沒有屏幕自適應。
2、Mono生命周期
分階段作展示,這里就不配圖了,主要是生命周期太長了
初始化:Awake -> OnEnable ->Start ->
當腳本實例被載入時,Awake()將會被調(diào)用,你可以在這里進行初始化操作。 GameObject如果為一開始setActive為false則一開始不會執(zhí)行。
當對象變?yōu)榧せ顮顟B(tài)時(active = true),就會調(diào)用這個方法。一般來說,添加委托或事件可以放在 OnEnable(),取消委托或事件可以放在 OnDisable()。
Awake Start一次,OnEnable設置enabled可多次執(zhí)行
物理計算:FixedUpdate -> OnTrigger/Collision->
游戲邏輯:InputEvent -> Update-> yield(喚醒掛起的協(xié)程,前面fixedUpdate也有yield) ->
動畫運算:OnAnimatorMove/IK(取決于Animator的 UpdateMode怎么選而有區(qū)別,如果是Normal則處于Update后,如果是Physics的話則處于FixedUpdate之后)
-> LateUpdate->
渲染:Scence Rendering -> Gizmos ->GUI ->
應用處理:OnApplicationPause -> OnApplicationQuit ->
OnApplicationQuit:在退出游戲之前,將在所有的游戲?qū)ο笊险{(diào)用該方法。如果是在編輯器中,那么就是當用戶點下停止按鈕時調(diào)用。
退出:OnDisable -> OnDestory
等Update 執(zhí)行完畢后 在去執(zhí)行LateUpdate,LateUpdate常用于攝像機跟隨等滯后操作,Update里適合寫邏輯
3、堆Heap棧Stack
堆中存儲的信息在被調(diào)用完畢不會立即被清理掉。
【申請速度】
堆的申請速度較慢,容易產(chǎn)生內(nèi)存碎片,但是用起來比較方便。
而棧的申請速度較快,但卻不受程序員的控制。
【申請大小】
棧申請的容量較小1-2M,堆申請大小雖受限于系統(tǒng)中有效的虛擬內(nèi)存,但較大
【存儲內(nèi)容】
棧負責保存我們代碼執(zhí)行或調(diào)用的路徑,而堆則負責保存對象或者說數(shù)據(jù)的路徑。
棧是自行維護的,也就是說內(nèi)存自動維護棧,當棧頂?shù)膬?nèi)容不再被使用,該內(nèi)容將會被跑出。相反,堆需要考慮垃圾回收。棧會保存函數(shù)的調(diào)用入口
如何決定放哪?
這里有一條黃金規(guī)則:
1.引用類型總是放在堆中。
2.值類型和指針總是放在他們被聲明的地方。
4、存儲的幾種方式
PlayerPref本地持久化
小的短的數(shù)據(jù),面板的屬性設置可以使用
每個變量一個key GetInt SetInt等方法,值可以在注冊表里查看
BinaryFormatter
二進制存儲,序列化、反序列化(強制類型轉(zhuǎn)換),字節(jié)流存儲,文件不具有可讀性
對于字節(jié)數(shù)組,使用FileStream寫入
save class要有serializable的特性
頭文件 system.IO
二進制文件大小端問題文件存儲不兼容?
JSON
JavaScript Object Notation
一種數(shù)據(jù)交換的格式,便于人的閱讀和編寫
常用于客戶端和服務器傳輸和整個場景的存儲信息
輕量的交換語言,格式壓縮,占用帶寬小,解析速度快
具有自我描述性,key-value鍵值對,作為文本格式即是一個string類型的
{ }表示對象,[ ]表示數(shù)組
創(chuàng)建對象存儲,序列化save對象為string,反序列化string變?yōu)閟ave對象
JsonUtility是unity自帶的解析工具FromJson和ToJson,FromJson 模板需要指定類型
向文件中寫入一些string時使用StreamWriter/Reader類,他對不同編碼有不同處理格式
常用Application.dataPath或Application.persistDataPath + “\name.json”,persistDataPath工程是隱藏的
C#中的List對象會變成Json的[ ]
需要自動換行的軟件幫助
XML
設計用來結(jié)構(gòu)化存儲和傳輸數(shù)據(jù)
eXtensible Markup Language:可標記擴展語言
有時大量的數(shù)據(jù)需要經(jīng)過轉(zhuǎn)換才能被讀取,部分不兼容的數(shù)據(jù)可能在這個過程中丟失
xml以純文本格式,本質(zhì)就是交換字符串,數(shù)據(jù)可以供各種數(shù)據(jù)使用
Tag是自定義的
可以使用XmlDocument類來保存、加載(System.Xml)
保存:
CreatElement創(chuàng)建節(jié)點并給出tag名字
AppendChild添加子節(jié)點
xmlElement.inerText可以獲取xmlElement節(jié)點的內(nèi)部信息
所有的節(jié)點都要按照實例化節(jié)點和添加的方式來使用
最后把root添加進XmlDocument里去,用save把它保存到一個text文件里
加載:
getElementsByTagName,可以獲得一個XmlNodeList,只有一個元素則獲取一個
同樣使用InerText加載到游戲數(shù)據(jù)中
存儲是一種樹狀結(jié)構(gòu)
相比JSON代碼量多很多,且里面有大量的冗余標簽(表示結(jié)構(gòu))
解析xml也要花費較多的時間
多數(shù)時候我們不需要冗余信息,但是一旦需要的時候沒有就是不行。
根據(jù)項目的需求選擇適合的
數(shù)據(jù)結(jié)構(gòu)類
1、Dictionary的插入時間復雜度?
Dictionary內(nèi)部實現(xiàn)為一個哈希表,通過設置好的哈希映射,達到常數(shù)級的時間復雜度。
2、平衡二叉樹的插入時間復雜度?
查詢是Log n的,查到應該插在哪即可用常數(shù)級去插入,合起來時間復雜度Log n。
3、手寫快排
快速排序思想:
關鍵步驟:1、選主元;2、兩個指針從兩頭掃描確定大于主元和小于主元的集合;3、對兩個區(qū)間遞歸
快速排序?qū)π∫?guī)模的數(shù)據(jù)不如使用插入排序,數(shù)據(jù)大概在1000左右時兩個性能差不多
void InsertionSort(vector& A, int left, int right)
{ /* 插入排序 */
int P, i;
int Tmp;
for (P = left + 1; P <= right; P++) {
Tmp = A[P]; /* 取出未排序序列中的第一個元素*/
for (i = P; i > left && A[i - 1] > Tmp; i--)
A[i] = A[i - 1]; /*依次與已排序序列中元素比較并右移*/
A[i] = Tmp; /* 放進合適的位置 */
}
}
int Median3(vector& A, int Left, int Right)
{
//采用頭中尾取中位數(shù)的方式確定主元,
//確定好主元之后再把主元移動到左端或右端保持一個連續(xù)的集合來給quickSort使用
int Center = (Left + Right) / 2;
if (A[Left] > A[Center])
swap(A[Left], A[Center]);
if (A[Left] > A[Right])
swap(A[Left], A[Right]);
if (A[Center] > A[Right])
swap(A[Center], A[Right]);
/* 此時A[Left] <= A[Center] <= A[Right] */
swap(A[Center], A[Right - 1]); /* 將基準Pivot藏到右邊*/
/* 只需要考慮A[Left+1] … A[Right-2] */
return A[Right - 1]; /* 返回基準Pivot */
}
void Qsort(vector& A, int Left, int Right)
{ /* 核心遞歸函數(shù) */
int Pivot, Cutoff, Low, High;
Cutoff = 1000;
if (Cutoff <= Right - Left) { /* 如果序列元素充分多,進入快排 */
Pivot = Median3(A, Left, Right); /* 選基準 */
Low = Left; High = Right - 1;
while (1) { /*將序列中比基準小的移到基準左邊,大的移到右邊*/
while (A[++Low] < Pivot);
while (A[--High] > Pivot);
if (Low < High) swap(A[Low], A[High]);
else break;
}
swap(A[Low], A[Right - 1]); /* 將基準換到正確的位置 */
Qsort(A, Left, Low - 1); /* 遞歸解決左邊 */
Qsort(A, Low + 1, Right); /* 遞歸解決右邊 */
}
else InsertionSort(A, Left, Right); /* 元素太少,用簡單排序 */
}
void QuickSort(vector& A, int N)
{ /* 統(tǒng)一接口 */
Qsort(A, 0, N - 1);
}
4、散列算法&&哈希沖突
散列算法:所謂查找就是已知對象找位置。如何快速搜索到需要的關鍵詞?如果關鍵詞是字符串不方便比較怎么辦(strcmp)?散列查找就是為了解決上面的問題,它主要做兩件事:計算位置、解決沖突;
通過構(gòu)造散列函數(shù)來計算關鍵詞的存儲位置,如果構(gòu)造的函數(shù)計算多個關鍵詞的存儲位置相同則要解決沖突。
他的時間復雜度是O(1),查找時間和問題規(guī)模無關,評價散列函數(shù)的性能主要看成功平均查找次數(shù)和不成功平均查找次數(shù),表中的元素不應當過多,裝填因子超過0.85或其他表的查找就會由于沖突而性能下降。
裝填因子公式:m為表的大小,n為元素個數(shù)
alpha = n / m
常見的計算位置的方法:
對數(shù)字:
直接定址:一個線性的安排
H(key) = a *key+b
除留余數(shù):TableSize為表的大小,一般取素數(shù)
H(key) = key % TableSize
數(shù)字分析:比如身份證號,取隨機性大的幾位作為地址
折疊法:56793542轉(zhuǎn)變?yōu)?542 + 793+056=1391 取三位391
平方取中法:顧名思義,把這個數(shù)平方然后取中間幾位,每一位對運算結(jié)果都有影響
對字母:
會想辦法把它映射成一個整數(shù)
前幾個字母ASCII相加求余:沖突比較嚴重,eat和tea等
移位法:讓每一位字母都起作用,每一位字母看成一個26進制的一個數(shù)字,然后按照進制轉(zhuǎn)換的方式變成一個10進制的值再和TableSize求余(用32是因為2五次方可以用位運算)
常見的解決沖突的辦法:
分離鏈接法:表是一個鏈表頭節(jié)點的結(jié)構(gòu)數(shù)組,沖突的關鍵詞放該位置的鏈表上,鏈長了查找效率會下降
線性探測:設置一個線性的增量序列:1,2,3,4,5...,在當前位置沖突了,就有
H_1(key) = (H(key)+i) mod TableSize
這樣的缺點是會有沖突聚集現(xiàn)象
平方探測:增量序列有變化 di = +-i^2,左看看右看看,一般結(jié)合TableSize為 = 4k+3保證平方探測法不會出現(xiàn)死循環(huán)而探測不全空間
上面兩種探測都屬于開放定址法:要注意Hash表刪除數(shù)據(jù)時并不能真的刪除,而是要打上標記,以防止其他因為這個結(jié)點而產(chǎn)生沖突的數(shù)據(jù)查找不到
雙哈希:沖突了就換個哈希算法再算一次
Resize表的大小:隨著元素變多則考慮把所有元素重構(gòu)一遍
設計模式類
1、MVC
Model模型對象
View 展示界面
Controller 控制器
用戶使用Controller里面的方法控制Controller關聯(lián)的一個Model,然后更新View視圖,Controller相當于一個訪問對象的中介器。
個人感覺unity、一般的3d建模、繪圖軟件的結(jié)構(gòu)都是MVC的,這種模式用于應用程序的分層開發(fā)。
2、工廠模式
管理對象創(chuàng)建,用來解耦編譯階段的new關鍵字而用工廠方法去完成對象的創(chuàng)建,調(diào)用者通過制定一個對象工廠來確定創(chuàng)建什么對象,是一種從編譯耦合到運行耦合的轉(zhuǎn)移
紅色為穩(wěn)定部分,一個是產(chǎn)品基類一個是工廠基類
總結(jié)
以上是生活随笔為你收集整理的unity算法面试_Unity面试准备的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: windows 下安装wamp环境
- 下一篇: 第14章:傅里叶变换