1.介绍
常用的排序算法主要有冒泡排序,选择排序,插入排序,希尔排序,堆排序,归并排序,快速排序,桶排序等。
2.实例演示
a.冒泡排序
当有一串无需数列待排序时,那么冒泡排序就会每次挑选出最大的数,置于这串数的末尾,然后从剩下的数中再挑选出最大的放置在末尾(这里的末尾应当指当前剩余未排列数组的末尾,即上次排好的数之前)。重复,直到最后一个数被排完。
// Array
var arr = [10, 20, 40, 60, 60, 0, 30]
/*
* 总共比较次数为arr.length-1次
* 每次的比较次数为arr.length-1次
* 依次递减
*/
var temp;//交换变量标识
// 两层for分别表示当前项与第二项
for(let i = 0; i < arr.length - 1; i++) {
for(let j = 0; j < arr.length - 1; j++) {
// 如果当前项大于第二项(后一项)则交换
if(arr[j] > arr[j+1]) {
temp = arr[j]
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
// 打印排序后的数组
console.log(arr)//输出结果为[0, 10, 20, 30, 40, 60, 60]
上述代码实现效果如下:
b.选择排序
即在一组无序数列中,每次选出最大或最小的数,放置在数列的开头,然后继续选出剩下数中最大或最小的数放在已选择数的后面,重复直到最后一个数被选完。
// Array
var arr = [10, 20, 40, 60, 60, 0, 30]
var temp;//交换变量标识
// 两层for分别表示当前项与第二项
for(let i = 0; i < arr.length - 1; i++) {
for(let j = i + 1; j < arr.length; j++) {
// 假设第二项是最小值(是则交换/否则继续比较)
if(arr[i] > arr[j]) {
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
// 打印排序后的数组
console.log(arr)//输出结果为[0, 10, 20, 30, 40, 60, 60]
上述代码实现效果如下:
c.插入排序
插入排序是一种最简单的排序,即在一组无序数列中,将数列分成有序和无序两部分,一般默认第一个数为已序,将第二个数按照排序准则插入已序数列,再将第三个数插入前两个数组成的已序数列,重复。直到最后一个数被插入。
// Array
var arr = [10, 20, 40, 60, 60, 0, 30]
// 排序算法
for(var i = 0; i < arr.length; i++) {
var n = i;
while(arr[n] > arr[n+1] && n >= 0) {
var temp = arr[n];
arr[n] = arr[n+1];
arr[n+1] = temp;
n--;
}
}
// 打印排序后的数组
console.log(arr)//输出结果为[0, 10, 20, 30, 40, 60, 60]
上述代码实现效果如下:
3.应用场景
(1)若n较小(如n≤50),可采用直接插入或直接选择排序。
当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接插人,应选直接选择排序为宜。
(2)若文件初始状态基本有序(指正序),则应选用直接插人、冒泡或随机的快速排序为宜;
(3)若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。
快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;
堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。这两种排序都是不稳定的。
若要求排序稳定,则可选用归并排序。但前面介绍的从单个记录起进行两两归并的排序算法并不值得提倡,通常可以将它和直接插入排序结合在一起使用。先利用直接插入排序求得较长的有序子序列,然后再两两归并之。因为直接插入排序是稳定 的,所以改进后的归并排序仍是稳定的。