前段时间帮助一个同学完成了一道Visual FoxPro的排序算法作业题,在此记录一下。
一、题目要求:
程序先要求使用者输入N个数,最后依次输出原始输入数列、从小到大排列后的数列、从大到小排列后的数列、两端大中间小排列后的数列。
二、程序代码:
三、编程思路:
首先,我们要用一个数组来接收用户输入的原始数据。根据用户指定的数据个数来定义数组维数,并逐个接收用户输入的数据保存到数组里。用户输入数据完毕,即可打印原始数列。
为了实现数据的从大到小、从小到大以及两头大中间小的排序,首先就要将该数组从小到大递增排序,然后实现另外两种排序就相对简单了。
对原始序列进行排序的方法很多,有冒泡排序、选择排序、希尔排序及插入排序等,这里选择使用插入排序算法。
总体的思路是假设已经有一个已经排序过的序列,向该序列中插入一个新的数据,新数据放在这个已经排序的序列中适当的位置,保证插入新数据后的序列还是一个有序序列。
对于一个长度为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间隔输出。