1、冒泡排序
冒泡排序思想:每一次对比相邻两个数据的大小,小的排在前面,如果前面的数据比后面的大就交换这两个数的位置 要实现上述规则需要用到两层for循环,外层从第一个数到倒数第二个数,内层从外层的后面一个数到最后一个数。 特点:排序算法的基础。简单实用易于理解,缺点是比较次数多,效率较低。 存在问题:数据的顺序排好之后,冒泡算法仍然会继续进行下一轮的比较,直到arr.length-1次,后面的比较没有意义的。 方案: 设置标志位flag,如果发生了交换flag设置为true;如果没有交换就设置为false。 这样当一轮比较结束后如果flag仍为false,即:这一轮没有发生交换,说明数据的顺序已经排好,没有必要继续进行下去。
function bubbleSort(arr) {
var len= arr.length;
var temp;//临时变量
var flag;
console.time("1.冒泡排序耗时")
for(var i=0;i<len;i++){
flag = false;
for(var j=len-1;j>i;j--){
if(arr[j]<arr[j-1]){
temp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = temp;
flag = true;
}
}
if(!flag) //flag = false,没发生交换
break;
}
console.timeEnd("1.冒泡排序耗时");
return arr;
}
function bubbleSort2(arr) {
var low = 0;
var high= arr.length-1; //设置变量的初始值
var tmp,j;
console.time('2.改进后冒泡排序耗时');
while (low < high) {
for (j= low; j< high; ++j) { //正向冒泡,找到最大者
if (arr[j]> arr[j+1]) {
tmp = arr[j]; arr[j]=arr[j+1];arr[j+1]=tmp;
}
}
--high; //修改high值, 前移一位
for (j=high; j>low; --j) { //反向冒泡,找到最小者
if (arr[j]<arr[j-1]) {
tmp = arr[j]; arr[j]=arr[j-1];arr[j-1]=tmp;
}
}
++low; //修改low值,后移一位
}
console.timeEnd('2.改进后冒泡排序耗时');
return arr;
}
//耗时最短
function bubbleSort3(arr) {
var low = 0;
var high= arr.length-1; //设置变量的初始值
var tmp;
console.time('3.改进后冒泡排序耗时');
while (low < high) {
var pos1 = 0,pos2=0;
for (let i= low; i< high; ++i) { //正向冒泡,找到最大者
if (arr[i]> arr[i+1]) {
tmp = arr[i]; arr[i]=arr[i+1];arr[i+1]=tmp;
pos1 = i ;
}
}
high = pos1;// 记录上次位置
for (let j=high; j>low; --j) { //反向冒泡,找到最小者
if (arr[j]<arr[j-1]) {
tmp = arr[j]; arr[j]=arr[j-1];arr[j-1]=tmp;
pos2 = j;
}
}
low = pos2; //修改low值
}
console.timeEnd('3.改进后冒泡排序耗时');
return arr;
}
2、选择排序
function selectionSort(arr) {
var len = arr.length;
var tmp,maxIndex;
console.time("选择排序耗时")
for (var i=0;i<len-1;i++){
maxIndex = i;
for(var j=i+1;j<len;j++){
if(arr[j]>arr[maxIndex]) //寻找最大值
maxIndex = j;
}
if(maxIndex != i){ //若最大值发生变化
tmp = arr[i];
arr[i] = arr[maxIndex];
arr[maxIndex] = tmp;
}
}
console.timeEnd("选择排序耗时");
return arr;
}
3、快速排序
思想:快速排序思想:先找到一个基准点(一般指数组的中部),然后数组被该基准点分为两部分,依次与该基准点数据比较,如果比它小,放左边;反之,放右边。左右分别用一个空数组去存储比较后的数据。最后递归执行上述操作,直到数组长度<=1; 特点:快速,常用。缺点是需要另外声明两个数组,浪费了内存空间资源。
function quickSort(arr) {
if(arr.length<=1){
return arr;
}
var pivotIndex = Math.floor(arr.length/2); //确定基准位置
var pivot = arr.splice(pivotIndex,1)[0]; //获取基准值
var left = [];
var right = [];
//console.time("快速排序耗时");
for (var i=0;i<arr.length;i++){
if(arr[i]<pivot){
left.push(arr[i]);
}else {
right.push(arr[i]);
}
}
//console.timeEnd("快速排序耗时");
return quickSort(left).concat([pivot],quickSort(right));
}
function quickSort1(arr) {
if(arr.length<=1)
return arr;
let left = [];
let right = [];
let q = arr[0];
for(let i=1,l=arr.length;i<l;i++){
if(arr[i]>q){
right.push(arr[i]);
}else{
left.push(arr[i]);
}
}
return quickSort1(left).concat([q],quickSort1(right));
}
4、归并排序
作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法: 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第2种方法) 自下而上的迭代 时间复杂度:O(n log n)
//采用自上而下递归
function mergeSort(arr) {
var len = arr.length;
if (len<2){
return arr;
}
var middle = Math.floor(len/2),
left = arr.slice(0,middle),
right = arr.slice(middle);
return merge(mergeSort(left),mergeSort(right));
}
function merge(left,right) {
var result = [];
while (left.length && right.length){
if (left[0] <= right[0]){
result.push(left.shift()); //left.shift(),删除数组的第一个元素,并返回该元素
}else{
result.push(right.shift());
}
}
while (left.length){
result.push(left.shift());
}
while (right.length){
result.push(right.shift());
}
return result;
}
5、插入排序
原理:对整个为排序的数列分为两个部分,一部分是已经排序好的,一部分是没有排序好的,每次都从还未排序好的数列中去除一个数,插入到已经排序好的数列之中,直到未排序的数列为零; 在排序过程中,一般默认将数列的第一个数作为已经排序好的数列,将剩余作为未排序好的数列
function insertSort(arr) {
var len = arr.length;
var temp, //存放数组元素
j; //索引
for (var i=1;i<len;i++){
j = i-1;
temp = arr[i];
while (j >= 0 && arr[j] > temp){
arr[j+1] = arr[j];
j--;
}
arr[j+1] = temp;
}
return arr;
}