案例:
(1)设待排序的关键字序列为{12、2、16、30、28、10、16*、20、6、18},试分别写出使用以下排序方法,每趟排序结束后关键字序列的状态。
-
直接插入排序
【算法思想】
①设待循环的记录存放在数组r[1…n]中,r[1]是一个有序序列。
②循环n-1次,每次使用顺序查找法,查找r[i](i=2、···、n)在已排好序的序列r[1···i-1]中的位置插入位置,然后将r[i]插入表长为i-1的有序序列r[1···i-1],直到将r[n]插入表长为n-1的有序序列r[1···n-1],最后得到一个表长为n的有序序列。
③直接插入排序算法是稳定排序算法;时间复杂度为O(n*n);空间复杂度为O(1)。
序列初始序列为{12、2、16、30、28、10、16*、20、6、18}
第一趟:{2、12、}16、30、28、10、16*、20、6、18
第二趟:{2、12、16、}30、28、10、16*、20、6、18
第三趟:{2、12、16、30、}28、10、16*、20、6、18
第四趟:{2、12、16、28、30、}10、16*、20、6、18
第五趟:{2、10、12、16、28、30、}16*、20、6、18
第六趟:{2、10、12、16、16*、28、30、}20、6、18
第七趟:{2、10、12、16、16*、20、28、30、}6、18
第八趟:{2、6、10、12、16、16*、20、28、30、}18
第九趟:{2、6、10、12、16、16*、18、20、28、30、} -
折半插入排序
【算法思想】
①设待循环的记录存放在数组r[1…n]中,r[1]是一个有序序列。
②循环n-1次,每次使用折半查找法(mid=(low+high)/2),查找r[i](i=2、···、n)在已排好序的序列r[1···i-1]中的位置插入位置,然后将r[i]插入表长为i-1的有序序列r[1···i-1],直到将r[n]插入表长为n-1的有序序列r[1···n-1],最后得到一个表长为n的有序序列。
③直接插入排序算法是稳定排序算法;时间复杂度为O(n*n);空间复杂度为O(1)。
序列初始序列为{12、2、16、30、28、10、16*、20、6、18}
第一趟:{2、12、}16、30、28、10、16*、20、6、18
第二趟:{2、12、16、30、28、10、16*、20、6、18
第三趟:{2、12、16、30、}28、10、16*、20、6、18
第四趟:{2、12、16、28、30、}10、16*、20、6、18
第五趟:{2、10、12、16、28、30、}16*、20、6、18
第六趟:{2、10、12、16、16*、28、30、}20、6、18
第七趟:{2、10、12、16、16*、20、28、30、}6、18
第八趟:{2、6、10、12、16、16*、20、28、30、}18
第九趟:{2、6、10、12、16、16*、18、20、28、30、} -
希尔排序(增量选用5、3、1)
【算法思想】
希尔排序实质上是采用分组插入的方法。先将整个待排记录序列分割成几组,从而减少参与直接插入排序的数据量,对每组分别进行直接插入排序,然后增加每组的数据量,重新分组。
这样当经过几次分组排序后,整个序列中的记录“基本有序”时,再对全体记录进行一次直接
插入排序。
希尔对记录的分组,不是简单地“逐段分割”,而是将相隔某个“增量”的记录分成
一组
①第一趟取增量d1(d1<n)把全部记录分成d1个组,所有间隔为d1的记录分在同一组,在各个组中进行直接插入排序
②第二趟取增量d2(d2<d1),重复上述的分组和排序。
③依次类推,直到所取的增量d=1(d<d1<<d2<d1)所有记录在同一组中进行直接插入排序为止。
序列初始序列为{12、2、16、30、28、10、16*、20、6、18}
第一趟:{10、2、16、6、18、12、16*、20、30、28}(增量为5)
第二趟:{6、2、12、10、18、16、16*、20、30、28}(增量为3)
第三趟:{2、6、10、12、16、16*、18、20、28、30}(增量为1) -
冒泡排序
【算法思想】
① 设待排序的记录存放在数组r[1中。首先将第一个记录的关键字和第二个记录的关键字进行比较,若为逆序(即r[1].keylr[2].key),则交换两个记录。然后比较第二个记录和第三个记录的关键字。依次类推,直至第n-1个记录和第n个记录的关键字进行过比较为止。上述过程称作第一趟起泡排序,其结果使得关键字最大的记录被安置到最后一个记录的位置上。
②然后进行第二趟起泡排序,对前n1个记录进行同样操作,其结果是使关键字次大的记录被安置到第n-1个记录的位置上。
③重复上述比较和交换过程,第i趟是从Lr[1]到Lr[ni+1]依次比较相邻两个记录的关键字,并在“逆序”时交换相邻记录,其结果是这n-i+1个记录中关键字最大的记录被交换到第n-i+1的位置上。直到在某一趟排序过程中没有进行过交换记录的操作,说明序列已全部达到排序要求,则完成排序。
④直接插入排序算法是稳定排序算法;时间复杂度为O(n*n);空间复杂度为O(1)
序列初始序列为{12、2、16、30、28、10、16*、20、6、18}
第一趟:{2、12、16、28、10、16*、20、6、18、[30]}
第二趟:{2、12、16、10、16*、20、6、18、[28、30]}
第三趟:{2、12、16、10、16*、6、18、[20、28、30]}
第四趟:{2、10、12、16、6、16*、[18、20、28、30]}
第五趟:{2、10、12、6、16、[16*、18、20、28、30]}
第六趟:{2、10、6、12、[16、16*、18、20、28、30]}
第七趟:{2、6、10、[12、16、16*、18、20、28、30]}
第八趟:{2、6、10、12、16、16*、18、20、28、30} -
快速排序
【算法思想】
在待排序的n个记录中任取一个记录(通常取第一个记录)作为枢轴(或支点)设其关键字为 pivotkey。经过一趟排序后,把所有关键字小于 pivotkey的记录交换到前面,把所有关键字大于 pivotkey的记录交换到后面,结果将待排序记录分成两个子表,最后将枢轴放置在分界处的位置。然后,分别对左、右子表重复上述过程,直至每一子表只有一个记录时,排序完成。
其中,一趟快速排序的具体做法如下。
(1)附设两个指针low和high,初始时分别指向表的下界和上界,设枢轴记录的关键字为 pivotkey(第一趟时,low=1;high=llength;)
.(2)从表的最右侧位置,依次向左搜索找到第一个关键字小于 pivotkey的记录和枢轴记录交换。具体操作是:当low<high时,若hig所指记录的关键字大于 pivotkey,则向左移动指针high(执行操作–high);否则将hig所指记录与枢轴记录交换。
(3)然后再从表的最左侧位置,依次向右搜索找到第一个关键字大于 pivotkey的记录和枢轴记录交换。具体操作是:当low<high时若low所指记录的关键字小于 pivotkey,则向右移动指针low(执行操作++low);否则将low所指记录与枢轴记录交换。
(4)重复步骤(2)和(3),直至low与high相等为止。此时low或high的位置即为轴在此趟排序中的最终位置,原表被分成两个子表。
在上述过程中,记录的交换都是与枢轴之间发生,每次交换都要移动3次记录,可以先将枢轴记录暂存在r[0]的位置上,排序过程中只移动要与枢轴交换的记录,即只做r[low]或
r[high]的单向移动,直至一趟排序结束后再将枢轴记录移至正确位置上。
序列初始序列为{12、2、16、30、28、10、16*、20、6、18}
第一趟:{6、2、10、12、28、30、16*、20、16、18} pivot=12
第二趟:{2、6、10、12、28、30、16*、20、16、18} pivot=6
第三趟:{2、6、10、12、18、16、16*、20、28、30} pivot=28
第四趟:{2、6、10、12、16*、16、18、20、28、30} pivot=18
第五趟:{2、6、10、12、16、16*、18、20、28、30} -
简单选择排序
【算法思想】
①设待排序的记录存放在数组r[1…n]中。第一趟从r[1]开始,通过1-1次比较,从n个记录中选出关键字最小的记录,记为t内,交换f1]和t因。
②第二趟从[2]开始,通过n-2次比较,从n-1个记录中选出关键字最小的记录,记为tk,交换r2]和r因。
③依次类推,第i趟从t[开始,通过n-i次比较,从-++1个记录中选出关键字最小的记录,记为t因,交换t[和r因。
④经过m-1趟,排序完成。
序列初始序列为{12、2、16、30、28、10、16*、20、6、18}
第一趟:{[2、]12、16、30、28、10、16*、20、6、18}
第二趟:{[2、6、]12、16、30、28、10、16*、20、18}
第三趟:{[2、6、10、]12、16、30、28、16*、20、18}
第四趟:{[2、6、10、12、]16、30、28、16*、20、18}
第五趟:{[2、6、10、12、16、]30、28、16*、20、18}
第六趟:{[2、6、10、12、16、16*、]30、28、20、18}
第七趟:{[2、6、10、12、16、16*、18、]30、28、20}
第八趟:{[2、6、10、12、16、16*、18、20、]30、28}
第九趟:{2、6、10、12、16、16*、18、20、28、30、} -
二路并归排序
【算法思想】
二路归并排序将R[low…high]中的记录归并排序后放入T[low…high]中当序列长度等于1时,递归结束,否则:
①将当前序列一分为二,求出分裂点mid=[(low+high)/2]
②对子序列R[low…mid]递归,进行归并排序结果放入S[low…mid]中
③对子序列R[mid+1…high]递归,进行归并排序,结果放入S[mid+1…high]中
④调用算法Merge,将有序的两个子序列S[low…mid]和S[mid+1…high]归为一个有序的序列T[low…high]
序列初始序列为{12、2、16、30、28、10、16*、20、6、18}
第一趟:{[2、12、] [16、30、] [10、28、] [16*、20、] [6、18]}
第二趟:{[2、12、16、30、] [10、16*、20、28、] [6、18]}
第三趟:{[2、10、12、16、16*、20、28、30、] [6、18]}
第四趟:{2、6、10、12、16、16*、18、20、28、30}
(2)给出如下关键字序列{321、156、57、46、28、7、331、33、34、63},试按链式基数排序方法,列出每一趟分配和收集的过程。
【算法思想】
第一趟分配对最低数位关键字(个位数)进行,改变记录的指针值将链表中的记录分配至10个链队列中去,每个队列中的记录关键字的个位数相等,一趟收集是改变所有非空队列的队尾记录的指针域,令其指向下一个非空队列的队头记录,重新将10个队列中的记录链成一个链表。
第二趟分配和第二趟收集是对十位数进行的,其过程和个位数相同。
第三趟分配和第三趟收集是对百位数进行的,过程同上。