下文全部以数组的从小到大排序为例,对象排序、从大到小排序同理。
冒泡排序法,是从数组的第一个数开始,依次向后比较相邻的两个数;前者比较大时,就将二者换位,这样一次遍历完成后,最大的数就在最后;之后再从第一个数开始向后比较(不比较最后一个数),依此类推。
选择排序法,是用数组的第一个数,依次和后面的数比较;后面的数小于第一个数时,将其置换到第一位,这样一次遍历完成后,第一个数就是最小的数;之后再从第二个数开始和后面比较,依此类推。
以前写冒泡排序法时,都是写完两个循环之后,用第一次外循环和最后一次外循环时比较的数组角标,来计算两个循环的初始值和条件表达式。今天觉得每次都要算一下这个好麻烦,然后想了想外循环和内循环的意义:
1 for(i = 0; i < N-1; i++) {//内循环进行次数:数组长度-1 2 //内循环:一次冒泡,循环完成后数组最后一个数是最大的数 3 for(j = 0; j < N-i-1; j++) {//比较进行次数:数组长度-已完成排序数量-1(已完成排序数量=内循环已完成次数=i) 4 if(buf[j] > buf[j+1]) { 5 temp = buf[j]; 6 buf[j] = buf[j+1]; 7 buf[j+1] = temp; 8 } 9 } 10 }
每次内循环完成后,数组最后一个数就是最大的数,因此一共需要进行(数组长度-1)次内循环,所以外循环的条件表达式为 i<N-1 ;
每次内循环中,需要比较的次数为剩余需要排序的数量-1次(最后一个数不需要和后面的数比较);又因剩余需要排序的数量=数组长度-已完成排序的数量,而已完成排序的数量=内循环完成次数,所以每次内循环需要进行(数组长度-内循环已完成次数-1)次比较,所以内循环的条件表达式为 j<N-i-1 。
这样理解就简单多了。
同时,也可以据此计算出一次冒泡排序法需要比较的次数:N(N-1)/2次。(N-i-1(i从0到N-2)的累加和)。
总结一下:
对于外循环,我们只关心内循环需要进行的次数,也就是把最大的数放到最后这个操作重复的次数(N-1次),因此外循环为 for(i = 0; i < N-1; i++) ;
对于内循环,我们只关心每次内循环比较的次数,也就是每次把最大的数放到最后需要比较的次数(N-i-1次),因此内循环为 for(j = 0; j < N-i-1; j++) ;
至于是从小到大排序,还是从大到小排序,这些事情就交给比较环节去改变就可以了。
同样的,对于选择排序法,有:
外循环需要从第一个数向后遍历,直到倒数第二个数,因此一共需要进行(数组长度-1)次内循环,所以外循环的条件表达式为 i<N-1 ,外循环为 for(i = 0; i < N-1; i++) ;
每次内循环中,已完成排序数量为i,而每次内循环都是从当前还没完成排序的第一个数,向后遍历到数组结尾,因此内循环为 for(j = i; j < N-1; j++) 。
同时,也可以据此计算出一次选择排序法需要比较的次数:N(N-1)/2次。(N-i-1(i从0到N-2)的累加和)。