(来源于百度图片)
特点:
交换的次数最多,所以它的性能是最差的
代码实现:
function bubbleSort(arr){ var len=arr.length; for(var i=0;i<len;i++){ for(var j=0;j<len-1-i;j++){ if(arr[j]>arr[j+1]){ //相邻元素两两对比var temp=arr[j+1]; //交互位置,所以大的都放到了最后面arr[j+1]=arr[j];arr[j]=temp;} } } return arr;}var arr=[2,3,6,4,2,1,90,100,20,5];console.log(bubbleSort(arr)); // [1, 2, 2, 3, 4, 5, 6, 20, 90, 100]插入排序
在插入排序中,数组会被划分为两种,“有序数组块”和“无序数组块”,
第一遍的时候从”无序数组块“中提取一个数20作为有序数组块。
第二遍的时候从”无序数组块“中提取一个数60有序的放到”有序数组块中“,也就是20,60。
第三遍的时候同理,不同的是发现10比有序数组的值都小,因此20,60位置后移,腾出一个位置让10插入。
然后按照这种规律就可以全部插入完毕。
下面是一张gif图
特点:
插入算法把要排序的数组分成两部分:
第一部分包含了这个数组的所有元素,但将第一个元素除外(让数组多一个空间才有插入的位置).
第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中
比冒泡排序快一点
代码实现:
//插入排序//假定当前元素之前的元素已经排好序,先把自己的位置空出来,//然后前面比自己大的元素依次向后移,直到空出一个"坑",//然后把目标元素插入"坑"中function insertSort(arr){ // 从第二个元素开始,因为要留出一个坑 for(var i=1;i<arr.length;i++){ var x=arr[i];for(var j=i-1;arr[j]>x;j--){ //后挪空出位置 .arr[j+1]=arr[j]; } if(arr[j+1]!=x){arr[j+1]=x; } } return arr;}var arr=[2,3,6,4,2,1,90,100,20,5];console.log(insertSort(arr,2)); // [1, 2, 2, 3, 4, 5, 6, 20, 90, 100]希尔排序
这里增量的取法如下:
第一次增量的取法为: d=count/2;
第二次增量的取法为: d=(count/2)/2;
最后一直到: d=1;
看上图观测的现象为:
d=3时:将40跟50比,因50大,不交换。
将20跟30比,因30大,不交换。
将80跟60比,因60小,交换。
d=2时:将40跟60比,不交换,拿60跟30比交换,此时交换后的30又比前面的40小,又要将40和30交换,如上图。
将20跟50比,不交换,继续将50跟80比,不交换。
d=1时:这时就是前面讲的插入排序了,不过此时的序列已经差不多有序了,所以给插入排序带来了很大的性能提高。
特点:
由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,
相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。
打个比方,我原来的数组是[5,4,3,2,1]的,这样一打乱就全部重新排了。
代码实现:
function shellSort(arr){ var gap=Math.floor(arr.length/2); while(gap>0){ for(var i=gap;i<arr.length;i++){temp=arr[i];for(var j=i;j>=gap&&arr[j-gap]>temp;j-=gap){arr[j]=arr[j-gap];}arr[j]=temp; } gap=Math.floor(gap/2); } return arr;}var arr = [2,3,6,4,2,1,90,100,20,5];console.log(shellSort(arr)); //[1, 2, 2, 3, 4, 5, 6, 20, 90, 100]归并排序
再来一张静态图,比较好理解
这里需要补充是,归并中对数组的分割是从上往下的,归并中数组的比较是从下往上的。
特点:
速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列.
属于分治思想,递归归并
代码实现:
/* 排序并合并*/function merge(left, right) { var re = []; while(left.length > 0 && right.length > 0) { if(left[0] < right[0]) { // 如果左边的数据小于右边的数据,将左边的数据取出,放到新数组那里re.push(left.shift()); } else {re.push(right.shift()); } } /* 当左右数组长度不等.将比较完后剩下的数组项链接起来即可 */ return re.concat(left).concat(right);}function mergeSort(arr) { if(arr.length == 1){ return arr; } /* 首先将无序数组划分为两个数组 */ var mid = Math.floor(arr.length / 2); var left = arr.slice(0, mid); var right = arr.slice(mid); /* 递归分别对左右两部分数组进行排序合并 */ return merge(mergeSort(left), mergeSort(right));}var arr=[2,3,6,4,2,1,90,100,20,5];console.log(mergeSort(arr)); // [1, 2, 2, 3, 4, 5, 6, 20, 90, 100]快速排序
2、所有小于"基准"的元素,都移到"基准"的左边;所有大于"基准"的元素,都移到"基准"的右边。
3、对"基准"左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。
特点:速度最快。和归并排序不同的是,归并排序是先分为两组再继续排,而快速排序是边分边排
代码实现:
// 大致分三步: // 1、找基准(一般是以中间项为基准) // 2、遍历数组,小于基准的放在left,大于基准的放在right // 3、递归 function quickSort(arr){ //如果数组<=1,则直接返回 if(arr.length<=1){return arr; } var pivotIndex=Math.floor(arr.length/2); //找基准,并把基准从原数组删除 var pivot=arr.splice(pivotIndex,1)[0]; //定义左右数组 var left=[]; var right=[]; //比基准小的放在left,比基准大的放在right for(var i=0;i<arr.length;i++){if(arr[i]<=pivot){left.push(arr[i]);}else{right.push(arr[i]);} } //递归 return quickSort(left).concat([pivot],quickSort(right)); } var arr=[2,3,6,4,2,1,90,100,20,5]; console.log(quickSort(arr)); // [1, 2, 2, 3, 4, 5, 6, 20, 90, 100]选择排序
静态图:
特点:可以说是冒泡排序的衍生品,效率比较一般般
代码实现:
// 在无序区中选出最小的元素,然后将它和无序区的第一个元素交换位置。function selectSort(arr){ length = arr.length; for (var i = 0; i < length; i++){ // 循环数组 var _min = arr[i]; // 把每一次的 数组里面的数字记录下来 var k = i; // 记录下来索引 for (var j = i + 1; j < length; j++){ // 当前的数字与后一个数字相比较if (_min > arr[j]){ //当前的数 大于 后面一个数的话_min = arr[j]; // 就讲后面 的数值 保存下来k = j;/// 保存索引} } arr[k] = arr[i]; // 进行交换位置 arr[i] = _min; } return arr;}var arr=[2,3,6,4,2,1,90,100,20,5];console.log(selectSort(arr)); // [1, 2, 2, 3, 4, 5, 6, 20, 90, 100]奇偶排序
gif图:
特点:奇数和偶数序列交替比较
代码实现:
function oddEvenSort(arr){ //swaped用来控制循环是否要继续,如果左边的都比右边的小,则退出循环,返回排好的数组 var swaped=true;var k=0; while(swaped){ if(k>0){swaped=false;} for(var i=k;i<arr.length-1;i+=2){if(arr[i]>arr[i+1]){// 如果左边的数字比右边的大,两者交换位置arr[i]=[ arr[i+1], arr[i+1]=arr[i] ][0]; swaped=true;} } k=[1,0][k]; //奇数和偶数之间的转行 } return arr;} var arr=[2,3,6,4,2,1,90,100,20,5];console.log(oddEvenSort(arr)); // [1, 2, 2, 3, 4, 5, 6, 20, 90, 100]总结