網上考試系統編製中的隨機抽取試題的四種演算法

來源:互聯網
上載者:User
演算法|隨機   因為教學的需要,我決定編寫一個asp+ms sql2000的網上考試系統,其功能主要為:實現判斷題、單項多項選擇題和填空題的線上自動答題、改卷;並將學生的錯誤答案記入資料庫,供教師分析。在編寫從題庫中隨機抽取試題這一模組的演算法上,卻頗費了一番周折,現將解決過程記錄如下,以供大家參考。

為了便於說明問題,文中提供的代碼中的變數pd為從題庫中要抽取出來考試的試題數量,資料庫表名與欄位名我都使用了中文,並僅以判斷題為例。

演算法一

由於不知道如何?從題庫中隨機抽取試題的sql語句,我在網上下載了幾個免費的考試系統進行研究,找到了第一種演算法,其思路為先將資料庫中所有資料讀出,獲得試題的總數後,產生一個1~(試題的總數-考試的試題數量)之間的隨機數,然後從這裡開始讀出資料:

<% set rs=server.CreateObject("ADODB.RecordSet")

    sql="select * from 判斷題 order by id asc"

    rs.open sql,conn,1,1

    mycound=rs.Recordcount '取得試題總數

randomize '初始化隨機數種子值

n=fix((mycound-pd+1)*Rnd+1)

rs.move n ‘指標移到n這個隨機數這個位置

for i=1 to pd

session("pdda")=session("pdda")&rs("正確答案")&"|" ‘用session來記錄標準答案

‘輸出試題及答案%>

  <tr> 

  <td width="10%" ><%=i%>、<%=rs("題目內容")%></td>

  <td align="center" width="10%" ><select name="cate<%=i%>"> 

  <option selected value=True>對</option> 

  <option value=False>錯</option></select> </td> 

   </tr> 

<% rs.movenext

next

rs.close%>

這種演算法基本上可以實現隨機抽取試題,並讓每個學生的試題和每一次重新整理以後的試題都不相同,但是它的最大不足在於試題的先後順序總是相同,特別是題庫中試題不多的時候,學生幾乎可以用背答案方法來應付考試了。雖然可以通過改變資料的排序方式來改變試題的先後順序,但變化總是不大。

演算法二

第二種演算法的思路很簡單,就是不斷產生1~題庫中的試題總數之間的隨機數,然後到資料庫中讀取這條記錄,直到滿足考試的試題量為止。

<%

set rs=server.CreateObject("ADODB.RecordSet")

    sql="select * from 判斷題 order by id asc"

    rs.open sql,conn,1,1

    mycound=rs.Recordcount '取得題庫中的試題總數

rs.close

for i=1 to pd 

randomize 

sid=int((mycound +1)*rnd+1) ‘產生1~題庫中的試題總數之間的隨機數

set rs=conn.execute("select * from判斷題where id="&sid) 

while rs.eof 

randomize 

sid=int((mycound +1)*rnd+1) 

set rs=conn.execute("select * from判斷題where id="&sid) ‘如果資料庫中找不到這條試題,就繼續產生隨機數讀取試題。

wend

session("pdda")=session("pdda")&rs("正確答案")&"|" ‘用session來記錄標準答案

‘輸出試題及答案%>

  <tr> 

  <td width="10%" ><%=i%>、<%=rs("題目內容")%></td>

  <td align="center" width="10%" ><select name="cate<%=i%>"> 

  <option selected value=True>對</option> 

  <option value=False>錯</option></select> </td> 

   </tr> 

<%

next

%>

這種演算法應該是真正意義上的隨機抽取試題,但是遺憾的是如果在題庫中題量不多的情況下,很容易會在資料庫中讀取重複的試題,如果再使用一個變數來儲存已經讀取過的試題id來解決試題重複的問題,演算法就過於繁瑣,是很不可取的。

  演算法二補充:

第二種演算法的思路很簡單,就是不斷產生1~題庫中的試題總數之間的隨機數,然後到資料庫中讀取這條記錄,直到滿足考試的試題量為止。當時我認為這種演算法應該是真正意義上的隨機抽取試題,但是遺憾的是如果在題庫中題量不多的情況下,很容易會在資料庫中讀取重複的試題,雖然也可以再使用一個變數或數組來儲存已經讀取過的試題id來解決試題重複的問題,演算法就過於繁瑣。為此,我片面地認為不可取的。其實用一個變數或數組來儲存已經讀取過的試題id,在演算法上並不繁瑣。

 

<%

寫一個產生隨機記錄的函數

Function rndtest(m_count,r_count) ''參數m_count為試題總數,r_count為要讀出的試題數

dim x,st,i

i=0

do while i>=r_count

randomize

x=fix(rnd*m_count)+1 ''產生1~m_count的隨機數

if not instr(st,x)>0 then

st=st&x&","  ''用,分割

i=i+1

end if

if i>=m_count then exit do ''如果m_count小於r_count將出現死迴圈,於是判斷並跳出迴圈

loop

rndtest=st

end function

set rs=server.CreateObject("ADODB.RecordSet")

       sql="select * from 判斷題 order by id asc"

       rs.open sql,conn,1,1

mycound =rndtest(rs.Recordcount, pd) '取得題庫中的試題總數

testcound=split(mycound, "'")

for i=0 to UBound(testcound)

rs.absoluteposition=matrix(i) ‘把記錄指標移指向第testcound (i)條記錄

session("pdda")=session("pdda")&rs("正確答案")&"|"  ‘用session來記錄標準答案

‘輸出試題及答案%>

   <tr> 

   <td  width="10%" ><%=i%>、<%=rs("題目內容")%></td>

    <td align="center" width="10%" ><select name="cate<%=i%>"> 

    <option selected value=True>對</option> 

    <option value=False>錯</option></select> </td> 

     </tr> 

<%

next

%>

演算法三

由於第二種演算法容易造成試題重複,為了避免系統產生重複的隨機數,我試著將題庫中試題總數均分為kp個範圍,讓每個範圍個產生一個隨機數,這樣就有效地避免了隨機數重複。

<% set rs=server.CreateObject("ADODB.RecordSet")

    sql="select * from 判斷題 order by id asc"

    rs.open sql,conn,1,1

    mycound=rs.Recordcount '取得試題總數

for i=1 to pd 

randomize 

temp=fix((fix(rs.Recordcount/pd)+1)*rnd+1) ‘產生1~題庫試題總數除以試卷試題數之間的隨機數

rs.move temp ‘指標移到隨機數位置

session("pdda")=session("pdda")&rs("正確答案")&"|" ‘用session來記錄標準答案

‘輸出試題及答案%>

  <tr> 

  <td width="10%" ><%=i%>、<%=rs("題目內容")%></td>

  <td align="center" width="10%" ><select name="cate<%=i%>"> 

  <option selected value=True>對</option> 

  <option value=False>錯</option></select> </td> 

   </tr> 

<%next

rs.close%>

這種演算法能夠有效地解決了演算法一和演算法二的不足,既做到了隨機抽取試題,又做到了試題不重複。但是仔細一想還是存在不足:就是題庫中的每一道試題出現的機率不相同,這樣就顯得不科學了。因為kp次都產生大數位機率是不大了,這樣排在後面的試題出現的機會就很小了。

演算法四

演算法四是我最後的研究結果,其演算法分為三步:

Setp1、擷取試題庫試題總數,然後產生一個1~試題總數的陣列。

Setp2、產生隨機數,將這個矩陣打亂。

Setp3、按順序取出陣列中的題目。

這種演算法和洗牌的原理相類似,圖示如下:

(設試題庫總數為10,要抽取出5道題)

Setp1:

陣列的初始內容如下:

A1

A2

A3

A4

A5

A6

A7

A8

A9

A10

1

2

3

4

5

6

7

8

9

10

Setp2:

產生兩個隨機數,如3和6。然後將A3和A6的內容交換,陣列的內容變為:

A1

A2

A3

A4

A5

A6

A7

A8

A9

A10

1

2

6

4

5

3

7

8

9

10

Setp3、按順序取出陣列中的題目A1~A5的內容,應該是1、2、6、4、5,讀出資料庫中相應的試題。

如果不斷迴圈Setp2,該陣列中的內容就隨機打亂,這樣既實現了隨機抽取試題的目的,又避免了試題抽取重複。

<%    

dim matrix() '定義變數數組

set rs=server.CreateObject("ADODB.RecordSet")

sql="select * from 判斷題order by id asc"

rs.open sql,conn,1,1

mycound=rs.Recordcount '取得試題總數

'設定陣列的初始值

for i=0 to mycound

matrix(i)=i+1

next

randomize '產生隨機數種子

for i=0 to 2*mycound ‘迴圈2*試題總數次

j=fix(rnd*mycound)   

k=fix(rnd*mycound)

'交換matrix(k)和matrix(j)的內容

temp=matrix(k)

matrix(k)=matrix(j)

matrix(j)=temp

next

'取出陣列中的題目,數量為試卷中該類題的數量

for i=1 to pd 

rs.absoluteposition=matrix(i) ‘把記錄指標移指向第matrix(i)條記錄

session("pdda")=session("pdda")&rs("正確答案")&"|" ‘用session來記錄標準答案

‘輸出試題及答案%>

  <tr> 

  <td width="10%" ><%=i%>、<%=rs("題目內容")%></td>

  <td align="center" width="10%" ><select name="cate<%=i%>"> 

  <option selected value=True>對</option> 

  <option value=False>錯</option></select> </td> 

   </tr> 

<%next

rs.close%>

演算法四補充:

當時無法解決定義一個足夠大的數組,於是用dim matrix(X),預設一個足夠大的數字X。雖然說暫時不會出現問題,但是如果資料庫中的試題數很大呢?總像一塊石頭擱在心中。呵呵。現在發現了ReDim語句,vbs參考中是這樣介紹ReDim 語句的:在過程級中聲明動態陣列變數並分配或重新分配儲存空間。這樣用ReDim matrix (rst.Recordcount)就可以完美地解決了這個問題。

<%       

Dim matrix()

set rs=server.CreateObject("ADODB.RecordSet")

sql="select * from 判斷題order by id asc"

rs.open sql,conn,1,1

mycound=rs.Recordcount  '取得試題總數

ReDim matrix(rst.Recordcount) ‘定義一個等於rst.Recordcount的數組

'設定陣列的初始值

for i=0 to mycound

matrix(i)=i+1

next

randomize  '產生隨機數種子

for i=0 to 2*mycound  ‘迴圈2*試題總數次

j=fix(rnd*mycound)     

k=fix(rnd*mycound)

'交換matrix(k)和matrix(j)的內容

temp=matrix(k)

matrix(k)=matrix(j)

matrix(j)=temp

next

'取出陣列中的題目,數量為試卷中該類題的數量

for i=1 to pd 

rs.absoluteposition=matrix(i) ‘把記錄指標移指向第matrix(i)條記錄

session("pdda")=session("pdda")&rs("正確答案")&"|"  ‘用session來記錄標準答案

‘輸出試題及答案%>

   <tr> 

   <td  width="10%" ><%=i%>、<%=rs("題目內容")%></td>

    <td align="center" width="10%" ><select name="cate<%=i%>"> 

    <option selected value=True>對</option> 

    <option value=False>錯</option></select> </td> 

     </tr> 

<%next

rs.close%>

總結:

相對來說,演算法四應該是最合理的。但是我不知道應該迴圈Setp2多少次,陣列中的數值最“隨機”,而且我不知道當試題庫的試題總數很多的情況下,這種演算法是否會很占系統資源,歡迎大家來信和我討論。



相關文章

Cloud Intelligence Leading the Digital Future

Alibaba Cloud ACtivate Online Conference, Nov. 20th & 21st, 2019 (UTC+08)

Register Now >

Starter Package

SSD Cloud server and data transfer for only $2.50 a month

Get Started >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。