結對編程作業——畢設導師智能匹配

結對編程作業——畢設導師智能匹配

031402317 李佳愷
031402511 黃家俊

問題描述及要求

  • 輸入30個老師(包含帶學生數的要求的上限,單個數值,在[0,8]內),100個學生(包含績點信息),每個學生有5個導師志愿(志愿的導師可以重復但不能空缺),要求另外寫生成程序隨機實現

  • 實現一個智能自動分配算法,根據輸入信息,輸出導師和學生間的匹配信息(一個學生只能有一個確認導師,一個導師可以帶少于等于其要求的學生數的學生) 及未被分配到學生的導師和未被導師選中的學生,要求輸出的未被導師選中的學生人數越少越好。

  • 為輸入輸出設計標準化、通用化、可擴展的接口,為該智能匹配程序模塊后期可能的整合入系統提供便利

  • 輸入輸出的格式,如采用文本文件或數據庫的方式輸入,可自由討論確定,但需要明確,為后期可能的整合入系統提供便利

  • 需要為智能匹配算法確立幾條分配或排序原則,比如 績點優先、或其他、或其他等等

編程語言:JAVA

模塊設計

  • 實體類(entity)

  • 全局類(global)

  • 方法類(method)

  • 測試類(test)

學生類和導師類的定義

/**學生實體類**/
public class Student {private String sName; // 學生姓名private float gradePoint; // 學生績點private int[] sapplication = new int[5]; // 學生志愿private int teacherId; // 已選中老師編號
/*** 教師實體類**/
public class Teacher {private int tId;  //教師編號private String tName;  //教師姓名private int sectionMax;  //區間最大值private int sectionRest;  //剩下人數    private List<Student> myStudent = new ArrayList<Student>(); //當前老師下的學生

生成程序代碼實現

1. 采用JAVA的random()函數在字符串區間中隨機選擇5個字符生成學生或導師的姓名

 //生成學生隨機姓名,教師姓名方法一樣public String createStudentName(){     String stringBase = "abcdefghijklmnopqrstuvwxyz";Random random = new Random();StringBuffer studentName = new StringBuffer();     for (int i = 0; i < 6; i++) {     int number = random.nextInt(stringBase.length()); studentName.append(stringBase.charAt(number));     }     return studentName.toString();          
}

2. random()函數可以產生[0,1]區間的小數,利用其隨機產生[1,5]區間的浮點數作為學生績點

//產生學生的績點
public float createGradePoint(){Random random = new Random();float gradePoint = random.nextFloat()*4+1;gradePoint =  (float) ((int)((gradePoint*100+5))/100.0);//取小數點后兩位return gradePoint;
}

3. 隨機產生[1,30]區間的整數作為學生志愿(整數對應導師的Id)

//產生學生的志愿
public int[] creatApplication(){int[] application = new int[5];Random random = new Random ();  boolean[]  bool = new boolean[30];  int randInt = 0;  /**得到5個不同的隨機數*/  for(int i = 0; i < 5 ; i++) {  do{  randInt  = random.nextInt(30);  }while(bool[randInt]);   bool[randInt] = true; application[i]=randInt+1;}return application;
}

4. 隨機產生[0.8]區間的整數作為老師帶學生數的上限

//產生區間上限
public int createSectionMax(){Random random = new Random();int sectionMax = random.nextInt(8);return sectionMax;
}

5. 定義集合來儲存100個學生和30個導師(setXXX()方法在學生類和導師類里面定義,用于學生或導師的信息的初始化,另創建class文件定義集合的全局變量)

//產生學生對象
public List<Student> createAllStudent(){CreateMember cm = new CreateMember();List<Student> studentList= new ArrayList<Student>();for(int i=0;i<100;i++){Student s = new Student(); s.setsName(cm.createStudentName());s.setGradePoint(cm.createGradePoint());s.setSapplication(cm.creatApplication());s.setTeacherId(0);studentList.add(s);}return studentList;
}//產生教師對象
public List<Teacher> createAllTeacher(){CreateMember cm = new CreateMember();List<Teacher> teacherList= new ArrayList<Teacher>();for(int i=1;i<=30;i++){Teacher t = new Teacher();t.settId(i);t.settName(cm.createTeacherName());int temp = cm.createSectionMax();Global.countAll+=temp;t.setSectionMax(temp);t.setSectionRest(temp);teacherList.add(t);}return teacherList;
}

匹配算法思想以及代碼實現

  • 志愿優先原則,五輪匹配,每輪從選擇學生上限未滿的導師Id出發,每個導師可以匹配到若干個當前輪次n,學生第n志愿是該老師Id的局部學生集合,并從集合中選擇學生

  • 考慮到在上述匹配到的局部學生集合當中學生應當有個排序以實現老師從中篩選出排名靠前的學生,于是這個排序就非常重要

  • 我們知道每個導師的熱門程度不同,因此我們定義學生未滿的導師有一個熱度值heat,并在每輪匹配算法的開始更新heat值,我們先遍歷當前輪次全部學生的集合(在代碼當中我們是從全部學生的集合當中刪掉每輪被選中的學生),得到每個導師共有幾個選他的學生sum,然后求出heat=sum/sectionRest(sectionRest為當前輪次老師剩余的選擇學生上限)

//設置教師熱度值
public class SetTeacherHeat {public void setHeat(){//遍歷還在參加選擇的教師for(Teacher teacher : Global.teacherList){//累計當前教師此輪的熱度值float heat = 0;//遍歷還在參加選擇的學生for(Student student : Global.studentList){//存儲學生志愿int[] tempValue = student.getSapplication();//當學生志愿與當前教師編號,不重復志愿for(int i=0;i<5;i++){if(teacher.gettId()==tempValue[i]){heat++;break;}                   }   }//設置當前教師的熱度值heat=heat/teacher.getSectionRest();teacher.setHeat(heat);                  }}}
  • 定義學生有一個綜合值composite,每輪匹配算法開始的時候更新其值,其值為該學生績點gradePoint * g + 該學生剩余志愿導師熱度值之和 * v,根據該值進行當前導師的局部學生集合的學生排序。老師選擇學生的時候看的是學生的績點,但是為了讓更多的學生能夠選到導師,我們認為可以看每個學生選的導師的熱度值之和,熱度值高代表其競爭壓力大,綜合績點和熱度值來進行排序。其中g + v = 1 ,其比例我們經過多次測試為g=0.5.v=0.5最為合理。

//獲得此輪當前學生臨時綜合值
public class GetTempComposite {public float getComposite(Student student,int round){//獲得學生志愿int[] tempValue = student.getSapplication();//記錄學生此輪綜合值int tempComposite=0;//變量此輪及之后學生志愿所選教師的熱度        for(int i=round;i<=round;i++){//志愿不重復,找到相符就跳出for(Teacher teacher : Global.teacherList ){//當前志愿與教師id相符if(tempValue[i]==teacher.gettId()){//累加tempComposite+=teacher.getHeat();break;}               }       }       return tempComposite;}}
    //更新學生綜合值,系數比例g,v;for(Student student : tempStudentList){GetTempComposite gtp = new GetTempComposite();float tempComposite = 0;tempComposite = gtp.getComposite(student, round);float composite=0;float gradePoints=0;gradePoints = student.getGradePoint();composite=gradePoints*g+tempComposite*v;        student.setComposite(composite);}
    // 實現學生按綜合值從大到小排序class SortByGradePoint implements Comparator {public int compare(Object o1, Object o2) {Student s1 = (Student) o1;Student s2 = (Student) o2;float temp1=s1.getComposite();float temp2=s2.getComposite();if (temp1 < temp2)return 1;else if (temp1 == temp2) {return 0;}return -1;}}
  • 進行第n輪匹配:

    1. 設置教師列表迭代器來遍歷導師集合
    // 設置教師列表迭代器Iterator<Teacher> teacherIterator = Global.teacherList.iterator();

2. for循環遍歷學生集合,學生第n志愿為當前導師的Id則列入局部學生集合變量

    List<Student> tempStudentList = new ArrayList<Student>();for (Student student : Global.studentList) {int[] application = student.getSapplication();//學生第round個志愿與教師匹配if (application[round] == teacher.gettId()) {// System.out.println(student.getsName() + "----此輪志愿選擇---"// + teacher.gettName());// 將此志愿的學生加到臨時列表中tempStudentList.add(student);}}

3. 如果集合內的學生總數大于等于老師的可選擇的學生人數上限,則根據集合內學生的排名,選擇排名靠前的等于老師選擇學生人數上限的學生,并把被選擇的學生從全部學生的集合中刪除,將導師的可選擇學生人數上限置零,并把該導師從導師集合中刪除

    // 按績點從大到小排序Collections.sort(tempStudentList, new SortByGradePoint());// 獲得該教師當前限選人數int sectionCurrent = teacher.getSectionRest();/*** 當前申請列表人數大于等于設置人數*/if (tempStudentList.size() >= sectionCurrent) {List<Student> myStudentList = new ArrayList<Student>();for (int i = 0; i < sectionCurrent; i++) {Student s = tempStudentList.get(i);myStudentList.add(s);// 將該學生列表添加到當前教師目錄下teacher.addStudent(s);// 將該學生從總學生列表中移除Global.studentList.remove(s);Global.countStu++;checked++;}// 更新該老師剩余人數為0sectionCurrent = sectionCurrent - sectionCurrent;teacher.setSectionRest(sectionCurrent);// 將當前教師存入已完成分配的集合中Global.doneTeacherList.add(teacher);// 將該老師從總教師列表中刪除teacherIterator.remove();}

4. 如果集合內的學生總數小于老師的可選擇的學生人數上限,則把集合內的學生添加到老師已選擇學生的集合里面,并把集合內的學生從全部學生的集合中刪除,將導師的可選擇學生人數上限更新

   else {/*** 當前申請人數小于限選人數*/sectionCurrent = sectionCurrent - tempStudentList.size();// 更新當前教師剩余人數teacher.setSectionRest(sectionCurrent);for (int i = 0; i < tempStudentList.size(); i++) {Student s = tempStudentList.get(i);// 將該學生添加到當前教師目錄下teacher.addStudent(s);// 將該學生從全局學生列表中移除Global.studentList.remove(s);Global.countStu++;checked++;}
}
  • 共五輪,在匹配算法方法中加入參數round表示第幾輪,另外建立class文件編寫主函數實現算法的調用

      public void allocteStudent(int round) {

這是我們進行g和v數值測量得到的結果


輸出和主函數

  • 在PrintUtils.java中定義方法輸出總的學生和導師信息以及調用匹配算法后詳細地結果


  • 在test.java中調用各種方法實現導師選擇以及最終輸出未被導師選擇的學生人數(輸出結果在附件中)

  • !!!!一次隨機輸入的輸出結果


總結

軟工第一次寫代碼很慌很慌,一開始是懵逼的,覺得很難的樣子,但其實只要開始認真地思考問題,總能慢慢地解析題目,找到突破點,以及通過揣摩老師的要求慢慢地完善代碼。代碼完成實現輸入輸出的那一刻很開心。

一次作業任務下來,我們討論了3次,花費了5個多小時,第一次討論圍繞了生成程序代碼的編寫和匹配算法的主要思想,這時候我們還沒有導師熱度值的想法,第二次是項目的建立以及git的使用,實現在coding.net上面提交代碼和文件,第三次是對匹配算法的優化,我們提出了熱度值的想法,一次一次的討論,都是為了能在作業當中獲得更高的分數,以及實現對自己的突破,并且博客的編寫也經過了兩個人多次的整合,努力完善博客的內容。

結對感受

  • 對于第一次結對編程,其中的感受是有好有壞的。好處在于兩個人的力量無疑比一個人強大很多,并且不是簡單的1+1,比如在生成程序和匹配算法思想的討論當中,我先提出自己的想法,隊友馬上就能在我的想法上面衍生出更多的想法,并且能發現對方想法當中的缺點并且共同思考改進的方法,提高了工作的效率和減少代碼編寫當中犯錯的次數。壞處在于代碼的分工,兩個人編寫代碼的習慣也不同,這就對代碼整合造成困難,這是我們作為一個團隊在合作當中需要磨合和學習的,所以在結對過程當中我們也認識到這個困難并克服。

  • 李佳愷:“黃家俊的編寫代碼的能力比我強很對,Java學的比我深入,比我熟悉,所以在結對當中他完成代碼的部分較多,所以工作量占得也比較多,而且這是主動去做的,這一點我很不好意思也很感謝,所以我也盡最大努力地寫好隨筆,希望能為兩個人獲得更高的分數,并且我需要加緊Java的學習,畢竟后面還有團隊的項目,加油!”

  • 黃家俊:“在此次結對編程中,感受最深的應該是團隊交流吧。在整個過程中我和佳愷的交流基本上不存在障礙,我們都能從對方的表達中得到明確的信息,很容易將各自表達的觀點擴展開來討論。其中很關鍵的一點是,在編碼過程中我遇到一個難題,自己一個人想了許久沒找到根源,然后在和佳愷交流過程中,靈光一閃,找到了解決的方法。所以在這次合作中,愈發感覺到團隊合作的重要性,希望之后還有合作的機會。”

我們的代碼----Coding.net

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/250623.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/250623.shtml
英文地址,請注明出處:http://en.pswp.cn/news/250623.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

內置函數二

內置函數: 1.lambda 匿名函數 lambda 參數:返回值 例    resultlambda x,y:xy sresult(x3,y4) print(s) 2.sorted 排序 sorted(iterable, keyfunc, reverseTurn/False) 例    lst [1, 8, 18, 19, 97, 12, 3] lst.sort() lst自帶的排序功能  l2 sorted(lst) 排序…

vue --- 2.0響應式補充

補充: 數組的響應式 // 對數組的方法進行重寫 // 1. 不能影響本來的方法 // 2. 調用的時候可以找到它 let odlArrayPrototype Array.prototype; let proto Object.create(odlArrayPrototype); // 繼承 [push,shift,unshift].forEach(method >{proto[method] function(){…

OptaPlanner - 把example運行起來(運行并淺析Cloud balancing)

經過上面篇長篇大論的理論之后&#xff0c;在開始講解Optaplanner相關基本概念及用法之前&#xff0c;我們先把他們提供的示例運行起來&#xff0c;好先讓大家看看它是如何工作的。OptaPlanner的優點不僅僅是提供詳細豐富的文檔 &#xff0c;還為各種應用場景提供豐富的示例&am…

es6 --- 使用proxy對數據進行劫持

說明: 數據劫持,簡單的說就是在對數據進行操作(增刪改查)時,觸發的函數下面想通過使用以下的形式來使用: let proxy reactive({ name:lz }); proxy.name; // 獲取 proxy.name 栗子; // 設置 delete proxy.name; // 刪除解決方案: proxy函數的2個參數第一個參數: 接收一…

Java8-如何構建一個Stream

Stream的創建方式有很多種&#xff0c;除了最常見的集合創建&#xff0c;還有其他幾種方式。 List轉Stream List繼承自Collection接口&#xff0c;而Collection提供了stream()方法。 List<Integer> list Lists.newArrayList(1, 2, 3); Stream<Integer> stream li…

軟件產品案例分析

軟件產品案例分析 第一部分&#xff1a; 評測&#xff1a; 上手體驗&#xff1a; 說實話&#xff0c;在老師布置這個作業之前我確實不知道有K米這個APP&#xff0c;我想這是很少去KTV的原因吧。。。不過在接到這個作業后&#xff0c;我就去百度了普及了一下這個app的相關知識。…

java/android 做題中整理的碎片小貼士(12)

1、edittext中設置最長字數&#xff0c;可在xml中加入android:maxLength"10"&#xff0c;可在java代碼中加入editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(20)}); 2、edittext監聽軟鍵盤delete按鍵&#xff1a; Et.setOnKeyListener(new Vi…

POJ2777(線段樹裸題)

題目&#xff1a;http://poj.org/problem?id2777 別忘了各地的return&#xff1b; 有可能輸入的L<R&#xff0c;手動swap&#xff1b; 似乎是多組輸入&#xff1f; pushup和pushdown的位置。 &#xff08;原來pushup只有一行&#xff09; 要開四倍數組。是這種寫法的原因吧…

vue --- 2.0 編譯的實現

初識 假設html中有如下dom: <div id"app"><!-- 插值綁定 --><p>{{name}}</p><!-- 指令解析 --><p l-text"name"></p><p>{{age}}</p><p>{{doubleAge}}</p><!-- 雙向綁定實現 -->…

個人作業收官——軟件工程實踐總結

一、回望與展望 1.1 對比現在和開學初博客開篇的課程目標和期待 當初的目標&#xff1a; 提升團隊合作的能力能夠學習到開發的一系列流程&#xff0c;以及如何寫高質量的代碼加強自己的編碼能力&#xff0c;以及編碼習慣熟悉不同平臺的開發過程 如今&#xff1a; 基本的目標都…

sklearn中SVM調參說明

寫在前面 之前只停留在理論上&#xff0c;沒有實際沉下心去調參&#xff0c;實際去做了后&#xff0c;發現調參是個大工程&#xff08;玄學&#xff09;。于是這篇來總結一下sklearn中svm的參數說明以及調參經驗。方便以后查詢和回憶。 常用核函數 1.linear核函數: K(xi,xj)xTi…

TZOJ 3030 Courses(二分圖匹配)

描述 Consider a group of N students and P courses. Each student visits zero, one or more than one courses. Your task is to determine whether it is possible to form a committee of exactly P students that satisfies simultaneously the conditions: every stude…

vue --- configureWebpack模擬后臺數據

初識 使用vue/cli搭建的項目可以在vue.config.js中,模擬一個后臺(express寫法)vue.config.js configureWebpack: {devServer: {// 模擬后臺服務器 express寫法before(app) {app.get(/api/login, function(req, res) {const { username, passwd } req.query;console.log(user…

TCP和UDP的優缺點及區別

轉自&#xff1a;http://www.cnblogs.com/xiaomayizoe/p/5258754.html TCP的優點&#xff1a; 可靠&#xff0c;穩定 TCP的可靠體現在TCP在傳遞數據之前&#xff0c;會有三次握手來建立連接&#xff0c;而且在數據傳遞時&#xff0c;有確認、窗口、重傳、擁塞控制機制&#xff…

e.getMessage 為空NULL

e.getMessage 為空NULL 在日常代碼中免不了要try catch 切忌用try catch 去try 整個方法。 在對象操作之前盡量寫上if 空判斷。 反例&#xff1a; public void send(){ try{ 代碼1&#xff1a;獲取對象 代碼2&#xff1a;操作代碼1 代碼3&#xff1a;操作代碼2 代碼4&#xff1…

Linux:客戶端的實現

寫了一個簡單的服務器軟件&#xff0c;但是沒有寫客戶端。現在我將客戶端實現了&#xff0c;其實昨天已經說了客戶端的實現步驟了。 步驟&#xff1a; socket() 初始化 connet()鏈接 從標準輸入讀數據fgets() 傳數據到服務器write() 讀從服務器返回的數據read() 寫數據到屏幕上…

vue --- http攔截,登錄登出的邏輯設計

設計 在src目錄下創建一個interceptor.js登錄邏輯 設置攔截,在發起請求前,先判斷用戶是否登錄(在本栗中,即是否能夠在瀏覽器緩存中找到token). 登出邏輯 對服務端傳過來的數據進行攔截,判斷其狀態碼是否為401(未登錄或token過期)清空瀏覽器緩存中的token重定向到登入頁面 inte…

循環分支循環語句

# 三大結構 - 循環 - 分支 - 循環 . . .In [ ]:# 分支 - 分支的基本語法 - if 條件表達式&#xff1a; 語句1 語句2 語句3 ..... - 條件表達式就是計算結果必須是布爾值的表達式 - 表達式后面的冒號覺對不能少 - 注意 if 后面出現的語句&#xff0c;如果屬于 if 語句塊&…

HTTP 1.1與HTTP 1.0的比較

HTTP 1.1與HTTP 1.0的比較 一個WEB站點每天可能要接收到上百萬的用戶請求&#xff0c;為了提高系統的效率&#xff0c;HTTP 1.0規定瀏覽器與服務器只保持短暫的連接&#xff0c;瀏覽器的每次請求都需要與服務器建立一個TCP連接&#xff0c;服務器完成請求處理后立即斷開TCP連接…