Java性能優(yōu)化之?dāng)?shù)據(jù)結(jié)構(gòu)實(shí)例代碼
—舉例(學(xué)生排課)—
正常思路的處理方法和優(yōu)化過(guò)后的處理方法:
比如說(shuō)給學(xué)生排課。學(xué)生和課程是一個(gè)多對(duì)多的關(guān)系。
按照正常的邏輯 應(yīng)該有一個(gè)關(guān)聯(lián)表來(lái)維護(hù) 兩者之間的關(guān)系。
現(xiàn)在,添加一個(gè)約束條件用于校驗(yàn)。如:張三上學(xué)期學(xué)過(guò)的課程,在排課的時(shí)候不應(yīng)該再排這種課程。
所以需要出現(xiàn)一個(gè)約束表(即:歷史成績(jī)表)。
即:學(xué)生選課表,需要學(xué)生成績(jī)表作為約束。
—方案一:正常處理方式—
當(dāng)一個(gè)學(xué)生進(jìn)行再次選課的時(shí)候。需要查詢(xún)學(xué)生選課表看是否已經(jīng)存在。
即有如下校驗(yàn):
//查詢(xún) 學(xué)生code和課程code分別為 A 和 B的數(shù)據(jù)是否存在 //list集合中存放 學(xué)生選課記錄全部的數(shù)據(jù) List<StudentRecordEntity> ListStudentRecord=service.findAll(); //查詢(xún)數(shù)據(jù),看是否已經(jīng)存在 StudentRecordEntity enSr=ListStudentRecord.find(s=>s.學(xué)生Code==A && s.課程Code==B); If(enSr==null){ //學(xué)生沒(méi)有選該課程 //.... }else{ //學(xué)生已經(jīng)選過(guò)該課程 //.... }
對(duì)于上面這種代碼的寫(xiě)法,非常的簡(jiǎn)練。而且也非常易懂。
首先,假設(shè)有5000個(gè)學(xué)生,100門(mén)課程。那么對(duì)于學(xué)生選課的數(shù)據(jù)集中,數(shù)據(jù)量將是5000*100.數(shù)據(jù)量會(huì)是十萬(wàn)級(jí)別的數(shù)量級(jí)。
在十萬(wàn)條數(shù)據(jù)中,查詢(xún)學(xué)生=A課程=B的一條記錄。執(zhí)行的效率會(huì)很低。因?yàn)閒ind方法的查詢(xún)也就是where查詢(xún),即通過(guò)遍歷數(shù)據(jù)集合來(lái)查找。
所以,使用上面的代碼。在數(shù)據(jù)量逐漸增長(zhǎng)的過(guò)程中,程序的執(zhí)行效率會(huì)大幅度下降。
ps:數(shù)據(jù)量增長(zhǎng),在該例子中并不太適合。例子可能不太恰當(dāng)??傊蟾啪褪沁@個(gè)意思。)
—方案二:使用內(nèi)存進(jìn)行優(yōu)化效率—
這種做法,需要消耗內(nèi)存?;蛘哒f(shuō)把校驗(yàn)的工作向前做(數(shù)據(jù)的初始化,在部署系統(tǒng)的過(guò)程中進(jìn)行)。即:在頁(yè)面加載的時(shí)候數(shù)據(jù)只調(diào)用提供的public方法進(jìn)行校驗(yàn)。
//學(xué)生Code 到 數(shù)組索引 Private Dictionary<string,int> _DicStudentCodeToArrayIndex; //課程Code 到 數(shù)據(jù)索引 Private Dictionary<string,int> _DicCourseCodeToArrayIndex; //所有學(xué)生 List<StudentEntity> ListStudent=service.findAllStudent(); //所有課程 List<CourseEntity> ListCourse=service.findAllCourse(); //所有 學(xué)生選課記錄 List<StudentCourseEntity> ListStudentRecord=service.finAll(); Private int[,] _ConnStudentRecord=new int[ListStudent.count,ListCourse.count]; //構(gòu)造 學(xué)生、課程的 數(shù)組 用于快速查找字典索引 Private void GenerateDic(){ For(int i=0; i<ListStudent.Count; i++) _DicStudentCodeToArrayIndex.Add(ListStudent[i].code,i) } For(int i=0; i<ListCourse.Count; i++){ _DicCourseCodeToArrayIndex.Add(ListCourse[i].code,i) } } //構(gòu)造學(xué)生選課 匹配的 二維數(shù)組。 1表示 學(xué)生已選該課程 Private void GenerateArray(){ Foreach(StudentRecordEntity sre in ListStudentRecord){ int x=_DicStudentCodeToArrayIndex[sre.學(xué)生Code]; int y=DicCourseCodeToArrayIndex[sre.課程Code]; ConnStudentRecord[x,y]=1; } } //對(duì)外公開(kāi)的方法:根據(jù)學(xué)生Code 和課程Code 查詢(xún) 選課記錄是否存在 /// <returns>返回1 表示存在。返回0表示不存在</returns> Public void VerifyRecordByStudentCodeAndCourseCode(String pStudentCode,String pCourseCode){ int x=_DicStudentCodeToArrayIndex[pStudentCode]; int y=_DicCourseCodeToArrayIndex[pCourseCode]; Return ConnStudentRecord[x,y]; }
—性能分析—
分析一下第二種方案的表象。
1、方法很多。
2、使用的變量很多。
首先要說(shuō)一下。該優(yōu)化的目的,是提高學(xué)生在選課的時(shí)候,所出現(xiàn)的卡頓現(xiàn)象(校驗(yàn)數(shù)據(jù)量大)。
分別對(duì)以上兩種方案進(jìn)行分析:
假設(shè)學(xué)生為N,課程為M
第一種方案:
時(shí)間復(fù)雜度很容易計(jì)算第一種方案最小為O(NM)
第二種方案:
1、代碼多。但是給用戶(hù)提供的只有一個(gè)VerifyRecordByStudentCodeAndCourseCode方法。
2、變量多,因?yàn)樵摲桨妇褪且褂脙?nèi)存提高效率的。
這個(gè)方法執(zhí)行流程:1、在Dictionary中使用Code找Index2、使用Index查詢(xún)數(shù)組。
第一步中,Dictionary中查詢(xún)是使用的Hash查找算法。時(shí)間復(fù)雜度為O(lgN)時(shí)間比較快。第二步,時(shí)間復(fù)雜度為O(1),因?yàn)閿?shù)組是連續(xù)的使用索引會(huì)直接查找對(duì)應(yīng)的地址。
所以,使用第二種方案進(jìn)行校驗(yàn),第二種方案時(shí)間復(fù)雜度為O(lgN+lgM)
—總結(jié)—
通過(guò)上面的分析,可以看出,內(nèi)存的付出是可以提高程序的執(zhí)行效率的。以上只是一個(gè)例子,優(yōu)化的好壞取決于使用的數(shù)據(jù)結(jié)構(gòu)。
以上就是本文關(guān)于Java性能優(yōu)化之?dāng)?shù)據(jù)結(jié)構(gòu)實(shí)例代碼的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專(zhuān)題,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!
相關(guān)文章
Java基礎(chǔ)知識(shí)精通二維數(shù)組的應(yīng)用
為了方便組織各種信息,計(jì)算機(jī)常將信息以表的形式進(jìn)行組織,然后再以行和列的形式呈現(xiàn)出來(lái)。二維數(shù)組的結(jié)構(gòu)決定了其能非常方便地表示計(jì)算機(jī)中的表,以第一個(gè)下標(biāo)表示元素所在的行,第二個(gè)下標(biāo)表示元素所在的列。下面簡(jiǎn)單了解一下二維數(shù)組,包括數(shù)組的聲明和初始化2022-04-04Quarkus中RESTEasy?Reactive集成合并master分支
這篇文章主要為大家介紹了Quarkus中RESTEasy?Reactive集成合并master分支的詳細(xì)作用分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-02-02SpringBoot使用Redis Stream實(shí)現(xiàn)輕量消息隊(duì)列的示例代碼
Redis Stream 是 Redis 5.0 引入的一種數(shù)據(jù)結(jié)構(gòu),用于處理日志類(lèi)型的數(shù)據(jù),它提供了高效、可靠的方式來(lái)處理和存儲(chǔ)時(shí)間序列數(shù)據(jù),如事件、消息等,本文介紹了SpringBoot使用Redis Stream實(shí)現(xiàn)輕量消息隊(duì)列,需要的朋友可以參考下2024-08-08Java Maven高級(jí)之插件開(kāi)發(fā)詳解
這篇文章主要介紹了Maven 插件開(kāi)發(fā)的詳細(xì)整理的相關(guān)資料,需要的朋友可以看下,希望能夠給你帶來(lái)幫助2021-09-09一文詳解Java過(guò)濾器攔截器實(shí)例逐步掌握
這篇文章主要為大家介紹了Java過(guò)濾器攔截器實(shí)例詳解逐步掌握,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04關(guān)于@Controller和@Restcontroller的那點(diǎn)奇葩事
這篇文章主要介紹了關(guān)于@Controller和@Restcontroller的那點(diǎn)奇葩事,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02