Visual FoxPro 的一个排序作业

     前段时间帮助一个同学完成了一道Visual FoxPro的排序算法作业题,在此记录一下。

 

一、题目要求:

        程序先要求使用者输入N个数,最后依次输出原始输入数列、从小到大排列后的数列、从大到小排列后的数列、两端大中间小排列后的数列。

二、程序代码:

  1. CLEAR
  2. NumCount = 0
  3. INPUT "   请输入需要排序的N个数:" to NumCount
  4. IF NumCount<1
  5.     ? "  输入的数据个数必须大于0!"
  6.     RETURN
  7. ENDIF
  8. DIME NumArr(NumCount)
  9. * Accept numbers from keyboard
  10. FOR i=1 TO NumCount
  11.     INPUT "   请输入第"+ALLTRIM( STR(i) )+"个数:" to NumArr(i)
  12. ENDFOR
  13. * Print Orginal numbers
  14. "   原始输入数列:"
  15. FOR i=1 TO NumCount
  16.     ?? ALLTRIM( STR( NumArr(i) ) ) + "  "
  17. ENDFOR
  18. * Sort the array
  19. FOR curIndex = 2 TO NumCount
  20.     curData         = NumArr( curIndex )
  21.     sortedMinIndex  = 1
  22.     sortedMaxIndex  = curIndex - 1                      
  23.     
  24.     * query the positon that the curData should put in
  25.     DO WHILE sortedMinIndex <= sortedMaxIndex
  26.         midIndex =  ( sortedMinIndex + sortedMaxIndex ) / 2
  27.         
  28.         IF NumArr( midIndex ) < curData
  29.             sortedMinIndex = sortedMinIndex + 1
  30.         ELSE
  31.             sortedMaxIndex = sortedMaxIndex - 1
  32.         ENDIF       
  33.     ENDDO
  34.     
  35.     *move data forward index from sortedMinIndex
  36.     FOR j = curIndex - 1 TO sortedMinIndex STEP -1
  37.         NumArr( j+1 ) = NumArr( j ) 
  38.     ENDFOR
  39.     
  40.     * put curData to its position
  41.     NumArr( sortedMinIndex ) = curData  
  42.     
  43. ENDFOR
  44. * Print data from min to max
  45. "   从小到大排序:"
  46. FOR i = 1 TO NumCount
  47.     ?? ALLTRIM( STR( NumArr(i) ) ) + "  "
  48. ENDFOR
  49. * Print data from max to min
  50. "   从大到小排序:"
  51. FOR i = NumCount TO 1 STEP -1
  52.     ?? ALLTRIM( STR( NumArr(i) ) ) + "  "
  53. ENDFOR
  54. * Print from both ends to center
  55. "   两端大中间小:"
  56. FOR i = NumCount TO 1 STEP -2
  57.     IF i>0
  58.         ?? ALLTRIM( STR( NumArr(i) ) ) + "  "
  59.     ENDIF
  60. ENDFOR
  61. IF i=0
  62.     startIndex = 1
  63. ELSE
  64.     startIndex = 2
  65. ENDIF
  66. FOR i = startIndex  TO NumCount STEP 2
  67.     IF i <= NumCount
  68.         ?? ALLTRIM( STR( NumArr(i) ) ) + "  "
  69.     ENDIF
  70. ENDFOR

三、编程思路:

        首先,我们要用一个数组来接收用户输入的原始数据。根据用户指定的数据个数来定义数组维数,并逐个接收用户输入的数据保存到数组里。用户输入数据完毕,即可打印原始数列。
为了实现数据的从大到小、从小到大以及两头大中间小的排序,首先就要将该数组从小到大递增排序,然后实现另外两种排序就相对简单了。
        对原始序列进行排序的方法很多,有冒泡排序、选择排序、希尔排序及插入排序等,这里选择使用插入排序算法。
总体的思路是假设已经有一个已经排序过的序列,向该序列中插入一个新的数据,新数据放在这个已经排序的序列中适当的位置,保证插入新数据后的序列还是一个有序序列。
        对于一个长度为N的原始序列a [1],a[2],…a[N],我们可以认为第一个数据a[1]是有序的(即这个有序序列只包含一个数据a[1]),这时我们将原始序列中第2个数据a[2]插入这个只包含一个数据的有序序列中,并保证插入后的序列“a[1],a[2]”仍然是有序的。至此,原始序列可以分为已排序和未排序的两个部分,第1个及第2个数据“a[1],a[2]”是有序的,第3个至第N个数据“a[3],a[4],…a[N]”仍然是未排序的。这时我们继续将第3个数据a[3]插入到有序序列中(包含第1个数据和第2个数据的序列“a[1],a[2]”)并保证插入后第1至第3个数据“a[1],a[2],a[3]”是有序的。依此类推,直到第N个数据插入到由第1个至第N-1个数据组成的   有序序列“a[1],a[2],…a[N-1]”中,并保证插入后这个N个数据都是有序的。
        一般的,假设序列中第1个至第i( 1<=i<N )个数据“a[1],a[2],…a[i]”是已经排序的,我们将第i+1个数据插入到第1至i-1个数据组成的序列中,为了保证插入后的包含i+1个数据的序列仍然有序,就要将第i+1个数据a[i+1]放在有序序列中适当的位置。
由于序列“a[1],a[2],…a[i]”是已经排序的,我们可以将数据a[i+1]与已经排序的序列按递增或递减方向依次做对比,以找到a[i+1]在有序序列中应该处在的位置。例如,将数据a[i+1]依次与数据a[1]、a[2]、…a[i]做比较,如果a[i+1]比当前比较的数据a[j] ( 1<=j<=I )小,则应将a[i+1]放在a[j]的位置,否则继续与下一个数据比较。
由于序列“a[1],a[2],…a[N]”是已经排序的,所以插入a[i+1]时可以采用“折中查找”算法,而不必将a[i+1]与有序数列中的数据逐个比较,大大减小比较次数,降低复杂度。将设m=(1+i)/2,即a[m]是a[1]…a[i]数列的中间数据,我们可以直接将a[i+1]与a[m]进行比较,如果a[i+1]>a[m],则继续将a[i+1]与“a[m+1]…a[N]”的中间数据进行比较,反之则与“a[1]…a[m-1]”的中间数据进行比较。依次类推,直至最终找到a[i+1]的位置。
        在进行a[1]…a[N]的排序后,就可以按1..N的顺序打印出递增数列及按从N…1的序列打印出递减数列。
为了打印出两头大中间小的序列,分两步打印。第一步从N..1的顺序间隔打印,即打印a[N]、a[N-2]、a[N-4]… a[3]、a[1]。(如果N是偶数则打印a[N]、a[N-2]、a[N-4]… a[4]、a[2])。第二步从1…N的顺序间隔打印a[2]、a[4]…a[N-1](如果N是偶数则打印a[1]、a[3]、…a[N-1])。

 

四、 程序分析


1. 将用户输入的“数据个数”保存到变量NumCount,声明一个长度为NumCount的数组NumArr,依次接收用户输入的数据保存到数组NumArr里。
2. 用一个循环输出数组NumArr里的所有数据,即输出用户输入的原始数列。
3. 对数组NumArr进行递增排序。从第2个数据开始至最后一个数据循环插入到前面已经排序的数列中。
1) curIndex 为当前循环中待插入的数据,即到此循环时,第1个到curIndex-1个数据是已经排序的;sortedMinIndex和sortedMaxIndex为已经排序的序列的最小和最大的索引;
2) 用折中查找法在已经排序的数列中找到第curIndex个数据应该存放的位置(即最终sortedMinIndex所在的位置);
3) 将sortedMinIndex的到curIndex-1的数据依次后移;
4) 将curIndex所在位置的原来数据放到sortedMinIndex位置上,从而达到从1到curIndex的数据都是排序过的目的。
4.将已经排序的数组NumArr从1到NumCount的顺序输出,即输出从小到大的数列;
5.将已经排序的数足从NumCount到1 的顺序输出,即输出从大到小的数列;
6.输出两头大中间小的数列:
   1)从NumCount到1的顺序间隔输出数列,既循环变量i的步长为-2。
   2) 第一步输出完毕后,最后一个输出的数据只能是NumArr数组的第一个数据或第二个数据,即循环终止后i的值是-1或0。如果i是0,则第一步最后输出的是NumArr的第2个数据,本次输出应该从第1个数据开始;否则上次最后输出的是NumArr的第1个数据,本次循环应该从2个数据开始输出。且本次循环直到NumCount间隔输出。

VFP中实现选择排序 时间:2009-06-07来源:编程入门网 作者:老马   众所周知在常用的简单排序方法中,前文所介绍的起泡排序(冒泡排序)是效率最差的一个了。我们今天所介绍的这个选择排序也是简单排序中的一种,不过比起泡排序的效率要高,并且也比较容易实现。   这些常用的排序方法多见诸于C/C++方面的资料中,如果要在vfp中实现这些排序方法,原理是一样的,只是在代码实现上略有差别。例如,在C/C++中数组的下标是从0开始,而vfp中数组的下标是从1开始;C/C++中的for语句可以采用for(i=0;i<n;i++)这种形式来同时完成变量赋初值、变量终值判断、变量递增这些操作,而vfp的for语句则有些弱,它的变量终值不能采取i<n这种形式来界定一个范围。因为以上的区别,在VFP中书写代码时要特别注意数组下标问题及循环变量的初值及终值,在以后的文章中不会再特别提及这些问题。   我们先看一下选择排序的基本思想和排序过程。(此部分内容引用自百度百科:http://baike.baidu.com/view/547263.htm)   基本思想   每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。   选择排序是不稳定的排序方法。n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果:    ①初始状态:无序区为R[1..n],有序区为空。    ②第1趟排序   在无序区R[1..n]中选出关键字最小的记录R[k],将它与无序区的第1个记录R[1]交换,使R[1..1]和R[2..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。   ……    ③第i趟排序   第i趟排序开始时,当前有序区和无序区分别为R[1..i-1]和R(1≤i≤n-1)。该趟排序从当前无序区中选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。   这样,n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果。   排序过程   【示例】:    初始关键字 [49 38 65 97 76 13 27 49]   第一趟排序后 13 [38 65 97 76 49 27 49]   第二趟排序后 13 27 [65 97 76 49 38 49]   第三趟排序后 13 27 38 [97 76 49 65 49]   第四趟排序后 13 27 38 49 [49 97 65 76]   第五趟排序后 13 27 38 49 49 [97 65 76]   第六趟排序后 13 27 38 49 49 65 [97 76]   第七趟排序后 13 27 38 49 49 76 [97 76]   最后排序结果 13 27 38 49 49 76 76 97   知道这个排序方法的基本思想和排序过程,在vfp中书写代码就简单了,只是需要注意vfp中数组的下标及循环变量的初值及终值与C/C++的区别。实例的运行界面如下图:   本例依然采取生成10个随机整数的方式取得数据,然后用选择法对这10个整数进行从小到大的排序。实现过程:   一、新建表单,向表单添加一个编辑框控件及三个命令按钮,按上图设置这三个命令按钮的caption属性。   二、添加代码:   1.“生成10个随机整数”按钮的click事件: public s(10) for i=1 to 10 s(i)=int(rand()*100) &&产生两位数的随机整数 thisform.edit1.value=thisform.edit1.value+str(s(i),5) endfor   2.“清屏”按钮的click事件:thisform.edit1.value=""   3.“选择排序”按钮的click事件: local i,j,k,t as integer for i=1 to 9 k=i for j=i+1 to 10 if s(j)<s(k) k=j endif endfor t=s(k) s(k)=s(i) s(i)=t endfor thisform.edit1.value="" for i=1 to 10 thisform.edit1.value=thisform.edit1.value+str(s(i),5) endfor
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值