需求:用户传入数字类型的数组,并传入排序规则(升序还是降序),实现数组排列,要求使用typescript实现
首先对传入的排序规则参数做一下约束,提高程序健壮性。rt
// 定义枚举类型,规定接收的排序规则参数只能是特定的值
enum SortType {
Asc = 'asc', //升序
Desc = 'desc' //降序
}
下面是算法的实现过程,它接收两个参数,数组和排序规则
// 传入的arr必须为数组类型,type参数表示要升序还是降序,且成员是数字,函数返回值为数字数组
function bubbleSort(arr:number[],type:SortType):number[] {
const length = arr.length;
for(let i = 0;i<length;i++){
// 用来判断某轮对比是否发生了交换
let isExchange = false;
// 外层循环每执行完一轮都能确定一个元素的最终位置,所以要减去i轮,这里再减1是因为每次都是用下标j和j+1进行比较的
for(let j = 0;j<length-i-1;j++){
if(type===SortType.Asc){
// 使用解构赋值来进行交换,使得代码更加简洁
(arr[j]>arr[j+1])?([arr[j], arr[j + 1]] = [arr[j + 1], arr[j]],isExchange = true):undefined
}else if(type===SortType.Desc){
(arr[j]<arr[j+1])?([arr[j], arr[j + 1]] = [arr[j + 1], arr[j]],isExchange = true):undefined
}
// 发生了交换,此时还不能确定排序是否完成,还需要进行下一轮循环
isExchange = true;
}
// 如果某轮循环没有发生元素的交换,则表示排序已经完成,直接结束算法执行返回数组
if(!isExchange){
break;
}
}
return arr
}
当中使用了一个变量isExchange 来判断此轮循环是否发生了元素交换,如果没有,则可以立马结束算法,节省了一定的性能。
下面是算法的执行过程,拿【5,3,6,2,9,1】来做演示实现升序排列:
第一轮冒泡:
比较 5 和 3,交换位置:[3, 5, 6, 2, 9, 1]
比较 5 和 6,不交换位置:[3, 5, 6, 2, 9, 1]
比较 6 和 2,交换位置:[3, 5, 2, 6, 9, 1]
比较 6 和 9,不交换位置:[3, 5, 2, 6, 9, 1]
比较 9 和 1,交换位置:[3, 5, 2, 6, 1, 9]
第二轮冒泡:
比较 3 和 5,不交换位置:[3, 5, 2, 6, 1, 9]
比较 5 和 2,交换位置:[3, 2, 5, 6, 1, 9]
比较 5 和 6,不交换位置:[3, 2, 5, 6, 1, 9]
比较 6 和 1,交换位置:[3, 2, 5, 1, 6, 9]
第三轮冒泡:
比较 3 和 2,交换位置:[2, 3, 5, 1, 6, 9]
比较 3 和 5,不交换位置:[2, 3, 5, 1, 6, 9]
比较 5 和 1,交换位置:[2, 3, 1, 5, 6, 9]
第四轮冒泡:
比较 2 和 3,不交换位置:[2, 3, 1, 5, 6, 9]
比较 3 和 1,交换位置:[2, 1, 3, 5, 6, 9]
第五轮冒泡:
比较 2 和 1,交换位置:[1, 2, 3, 5, 6, 9]
最终排序结果应该是:[1, 2, 3, 5, 6, 9]
下面是该算法的使用以及真机的运行结果:
const sortArr = [5,3,6,2,9,1]
const newArr = bubbleSort(sortArr,SortType.Asc)
console.log(newArr)
const newArr = bubbleSort(sortArr,SortType.Desc)
总结一下:
时间复杂度:该算法的最好时间复杂度是O(n),也就是当待排序数组基本按序排列时;最坏时间复杂度为O(n²) ,也就是当数组完全逆序时。平均复杂度为O(n²)。
空间复杂度:该算法只创建了常量级别的变量,因此空间复杂度为O(1)。
稳定性:当遇到数组当中又两个相同的值的时候,默认不交换位置,因此该算法是稳定的。