各种排序及其复杂度
插入排序(稳定)
function insertSort(arr){
var temp;
for( var i = 1 ; i <= arr.length-1 ; i++){
//取出"分界线"右边第一位,作为temp(本轮循环就你了)
temp = arr[i];
//设"分界线"左边第一位的下标,作为j
j = i-1;
while(j>=0 && arr[j] > temp){
arr[j+1] = arr[j];//二话不说,直接后挪一位
--j;
}
//挪后插
arr[j+1] = temp;
}
return arr;
}
思想:
0、分“有序组”(左手已拿到并已排序的牌)、“无序组”(右手抽到的牌);
1、起初“分界线”在下标0和1之间;
2、取“分界线”右边第一位,作为temp(分界线后面的,在本轮先不管,因为表示还没抽到的牌啦);
3、设“分界线”左边第一位的下标,作为 j;
4、j = i-1,这样 j 就离 i 更近了;
5、当 j >= 0 ,并且 arr[ j ] > temp,可插,那就二话不说,直接将那大块只挪到后一位。被大块只覆盖掉的朋友你别怕,你肯定是已经被抽取出来的啦;
6、然后再while循环,如果没有再出现比你这个temp大的还好;若有,这“第二大块只”也直接覆盖掉刚刚“大块只”的地方。不用担心,大块只已早就分身有术了;这时候 j 已跑在前沿了~
7、好啦,如果再没有出现过,那就是不用循环了;将arr[ j+1 ] = temp;temp要的位置就是你啦!
8、然后将分界线向右走一个单位,重复2~7,假装又取了一张牌;
快速排序(不稳定!)
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));
}
选择排序(不稳定!)
function selectSort(arr){
var min,temp;
for(var i = 0 ; i < arr.length-1 ; i++){
min = arr[i];
for(var j = i+1; j < arr.length ; j++){
if(arr[j] < min){
temp = min;
min = arr[j];
arr[j] = temp;
}
}
arr[i] = min;
}
return arr;
}
思想:
0、一共会进行 arr.length - 1轮的比赛;
1、从左边第一个数(即 i=0)开始,拷贝他,作为“天选之子”放到min;
2、将它后面一直觊觎着这个皇位的人,一个个和这个min比较。谁赢了,谁也拷贝一份做min,然后将min扔到走掉的那个人的位置,一直到最后一个觊觎的小人;
3、就在本次循环后,min里的数,放到当前的i处;
4、本轮比赛结束,i++
冒泡排序(稳定)
var arr = [2,88,6,8,3,0,34,72];
var sort = {};
sort.bubbleSort = function (arr) {
if (arr.length <= 1) {
return arr;
}
//i表示比较的轮数
for (var i = 0; i < arr.length - 1; i++) {
//比较i轮,把i个最大数放在数组后面,排数这i个数
for (var j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
console.log("第" + i + "轮:arr=[" + arr + "]");
}
};
sort.bubbleSort(arr);
console.log(arr);
第0轮:arr=[2,6,8,3,0,34,72,88]
第1轮:arr=[2,6,3,0,8,34,72,88]
第2轮:arr=[2,3,0,6,8,34,72,88]
第3轮:arr=[2,0,3,6,8,34,72,88]
第4轮:arr=[0,2,3,6,8,34,72,88]
第5轮:arr=[0,2,3,6,8,34,72,88]
第6轮:arr=[0,2,3,6,8,34,72,88]
[0, 2, 3, 6, 8, 34, 72, 88]
希尔排序(不稳定!)
function shallSort(array) {
var increment = array.length;
var i
var temp; //暂存
var count = 0;
do {
//设置增量
increment = Math.floor(increment / 3) + 1;
for (i = increment ; i < array.length; i++) {
console.log(increment);
if (array[i] < array[i - increment]) {
temp = array[i];
for (var j = i - increment; j >= 0 && temp < array[j]; j -= increment) {
array[j + increment] = array[j];
}
array[j + increment] = temp;
}
}
}
while (increment > 1)
return array;
}
归并排序(稳定)
归并排序:其基本思想是分治策略,先进行划分,然后再进行合并。
假设要对数组C进行归并排序,步骤是:
1.先将C划分为两个数组A和B(即把数组C从中间分开)
2.再分别对数组A、B重复步骤1的操作,逐步划分,直到不能再划分为止(每个子数组只剩下一个元素),这样,划分的过程就结束了。
function merge(left, right) {
var result = [];
while(left.length > 0 && right.length > 0) {
if(left[0] < right[0]) {
result.push(left.shift());
}
else {
result.push(right.shift());
}
}
/* 当左右数组长度不等.将比较完后剩下的数组项链接起来即可 */
return result.concat(left).concat(right);
}
function mergeSort(arr){
if(arr.length==1) {return arr};
var mid=Math.floor(arr.length/2);
var left_arr=arr.slice(0,mid),right_arr=arr.slice(mid);
return merge(mergeSort(left_arr),mergeSort(right_arr));
}
var arr=[12,20,30,21,15,33,26,19,40,25];
console.log(mergeSort(arr));