java性能优化——数据结构

来源:互联网 发布:centos设置u盘启动 编辑:程序博客网 时间:2024/05/24 06:39

—举例(学生排课)—

正常思路的处理方法和优化过后的处理方法:
比如说给学生排课。 学生 和 课程 是一个多对多的关系。 


按照正常的逻辑 应该有一个关联表来维护 两者之间的关系。 


现在,添加一个约束条件用于校验。如:张三上学期学过的课程,在排课的时候不应该再排这种课程。 



 所以需要出现一个约束表(即:历史成绩表)。



即:学生选课表,需要 学生成绩表作为约束。

—方案一:正常处理方式—

当一个学生进行再次选课的时候。需要查询学生选课表看是否已经存在。

即有如下校验:
[csharp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. //查询 学生code和课程code分别为  A 和 B的数据是否存在  
  2.   
  3. //list集合中存放  学生选课记录全部的数据  
  4. List<StudentRecordEntity> ListStudentRecord=service.findAll();     
  5. //查询数据,看是否已经存在  
  6. StudentRecordEntity enSr=ListStudentRecord.find(s=>s.学生Code==A && s.课程Code==B);  
  7. If(enSr==null){  
  8.     //学生没有选该课程  
  9.     //....  
  10. }else{  
  11.     //学生已经选过该课程  
  12.     //....  
  13. }  
对于上面这种代码的写法,非常的简练。而且也非常易懂。 

  首先,假设有5000个学生,100门课程。那么对于学生选课的数据集中,数据量将是5000*100.数据量会是十万级别的数量级。
  在十万条数据中,查询 学生=A 课程=B的 一条记录。执行的效率会很低。因为find方法的查询也就是where 查询,即通过遍历数据集合 来查找。 

  所以,使用上面的代码。在数据量逐渐增长的过程中,程序的执行效率会大幅度下降。 
  ps:数据量增长,在该例子中并不太适合。例子可能不太恰当。总之,大概就是这个意思。)

方案二:使用内存进行优化效率

  这种做法,需要消耗内存。或者说把校验的工作向前做(数据的初始化,在部署系统的过程中进行)。即:在页面加载的时候数据只调用提供的public方法进行校验。
[csharp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. //学生Code  到   数组索引  
  2. Private Dictionary<string,int> _DicStudentCodeToArrayIndex;  
  3. //课程Code  到   数据索引  
  4. Private Dictionary<string,int> _DicCourseCodeToArrayIndex;  
  5.   
  6. //所有学生  
  7. List<StudentEntity> ListStudent=service.findAllStudent();  
  8. //所有课程  
  9. List<CourseEntity> ListCourse=service.findAllCourse();  
  10. //所有 学生选课记录  
  11. List<StudentCourseEntity> ListStudentRecord=service.finAll();  
  12.   
  13. Private int[,] _ConnStudentRecord=new int[ListStudent.count,ListCourse.count];  
  14.   
  15. //构造 学生、课程的  数组 用于快速查找字典索引  
  16. Private void GenerateDic(){  
  17.     For(int i=0;i<ListStudent.Count;i++)  
  18.         _DicStudentCodeToArrayIndex.Add(ListStudent[i].code,i)  
  19.     }  
  20.     For(int i=0;i<ListCourse.Count;i++){  
  21.         _DicCourseCodeToArrayIndex.Add(ListCourse[i].code,i)  
  22.     }  
  23. }  
  24.   
  25. //构造学生选课 匹配的 二维数组。 1表示 学生已选该课程  
  26. Private void GenerateArray(){  
  27.   
  28.     Foreach(StudentRecordEntity sre in ListStudentRecord){  
  29.         Int x=_DicStudentCodeToArrayIndex[sre.学生Code];  
  30.         Int y=DicCourseCodeToArrayIndex[sre.课程Code];  
  31.         ConnStudentRecord[x,y]=1;  
  32.     }  
  33. }  
  34.   
  35. //对外公开的方法:根据学生Code 和课程Code  查询 选课记录是否存在  
  36. /// <returns>返回1 表示存在。返回0表示不存在</returns>  
  37. Public void VerifyRecordByStudentCodeAndCourseCode(String pStudentCode,String pCourseCode){  
  38.     Int x=_DicStudentCodeToArrayIndex[pStudentCode];  
  39.     Int y=_DicCourseCodeToArrayIndex[pCourseCode];  
  40.   
  41.     Return ConnStudentRecord[x,y];  
  42. }  

性能分析

分析一下第二种方案的表象。 
  1、方法很多。 
  2、使用的变量很多。

  首先要说一下。该优化的目的,是提高学生在选课的时候,所出现的卡顿现象(校验数据量大)。
分别对以上两种方案进行分析:
  假设学生为N,课程为M
第一种方案: 
  时间复杂度很容易计算 第一种方案最小为O(NM) 
第二种方案: 
  1、代码多。但是给用户提供的只有一个VerifyRecordByStudentCodeAndCourseCode方法。 
  2、变量多,因为该方案就是要使用内存提高效率的。 
  这个方法执行流程:1、在Dictionary中使用Code找Index 2、使用Index查询数组。

  第一步中,Dictionary中查询是使用的Hash查找算法。时间复杂度为O(lgN) 时间比较快。第二步,时间复杂度为O(1),因为数组是连续的使用索引会直接查找对应的地址。 
  所以,使用第二种方案进行校验,第二种方案时间复杂度为O(lgN+lgM) 


—总结—

  通过上面的分析,可以看出,内存的付出是可以提高程序的执行效率的。以上只是一个例子,优化的好坏取决于使用的数据结构。
0 0
原创粉丝点击