js随机数生成与排序
'use strict'; // 排序算法、 // 生成一个指定数量的不含重复数字的随机数组 function ranArr(n,callback) { var res = []; var tmp ; res = lack(res,n); ckRanArr(res,n,0,function (res) { return callback(res); }); } // 生成一个指定范围内(正整数 a到b)的随机数 function ranNum(a,b){ var n = Math.abs(a - b ); var base_n = a; if(a > b){ base_n = b; } var res = Math.floor(Math.random()*n) + base_n; return res; } // 返回去除重复项后的数组 function quchong(arr) { var arr2 = arr.slice(0); var arr2_len = arr2.length; var arr3 = []; for(var j = 0;j < arr2_len;j++){ // 重复项不进新数组 去重 (function (item,ind) { var flag = false; for(var k = (ind + 1);k < arr2_len; k++){ if(item == arr2[k]){ flag = true; } } if(!flag){ arr3.push(item); } }) (arr2[j],j); } return arr3; } // 补缺失的量并检查 function lack(arr,n) { // 去重后数量少了 补上 var arr_len = arr.length; if(arr_len < n){ var lack = n - arr_len; for(var j = 0; j < lack;j++){ arr.push( ranNum(0,100000000) ); } } return arr; } // 递归检查函数 count:重试次数 重试次数限制与生成数量相关 function ckRanArr(arr,n,count,callback){ var limit; if(n < 1000){ limit = 10*n; } if(n >= 1000){ limit = n; } if(count < limit){ count++; var arr2 = quchong(arr); // 去重 if(arr2.length < n ){ var arr3 = lack(arr2,n); // 补量 ckRanArr(arr3,n,count,callback); } else{ return callback(arr2); } } else{ return callback( quchong(arr) ); } } ranArr(10,function (res) { console.log(res); });
// 上面的递归调用会发生每个函数都是一个栈,会生成一个不断堆叠的函数栈直到最后一个栈函数return后依次退出。
// 同步循环生成版 function ranArr2(n){ var arr = []; arr = lack(arr,n); var limit; if(n < 1000){ limit = 10*n; } else{ limit = n; } cl:for(var i = 0;i < limit;i++){ console.log(i); var arr2 = quchong(arr); // 去重 if(arr2.length < n){ arr = lack(arr2,n); // 补量 } else{ break cl; } } return arr; }
优化性能效率版
// 前两个版本生成指定数量不重复的随机数效率太低了, // 举例生成1000个 每一次去重时都需要接近1000 x 1000次的比较 // 优化之后速度有了极大的提升 // 生成范围 0-30000 生成20000个不重复随机数 // ranArr2 平均需要23s(秒)左右 // ranArr3 平均需要300ms左右 //在数据范围和数据量接近 重复几率大的时候1位1位排重的方式具有很高的性能 //在数据范围和数据量差距很大 10万条 1亿 ran3平均需要5s左右 ran2需要23s左右 // 数据范围增加100倍 10万条 ran2 21s左右 function ranArr3(n) { var arr = []; var arr2 = []; if(n <= 0){ return arr2; } arr = lack(arr,n); arr2.push(arr[0]); // console.log('第0个数:'+arr2); var arr_len = arr.length; for (var i = 1; i < arr_len; i++) { // console.log('第'+i+'个数:'+arr[i]); arr2 = not_in_arr_item(arr[i],i,arr2 ); // console.log('得到arr2为:['+arr2+']'); } return arr2; } // 给定一个数组 和元素,返回一个不在数组中已有元素的元素 function not_in_arr_item(item,ind,arr2) { //console.log( '每次进入: '+ 'item:' + item + ' ind:' + ind + ' [' + arr2 + ']'); var flag = false; cl:for (var j = 0; j < ind; j++) { // console.log('j:'+j); if(item == arr2[j]){ flag = true; break cl; } } // console.log(flag); if(flag){ item = ranNum(0,100000000000); //console.log('进入ran: '+item); return not_in_arr_item(item,ind,arr2); } if(!flag){ arr2.push(item); return arr2; } }
排序算法部分
// 取5次的平均时间 // 比较 (个数) 冒泡 快速排序 插入排序 // 100 0.354ms 0.443ms 0.294ms // 1000 2.94ms 2.351ms 1.89ms 1.84ms // 10000 158.39ms 12.15ms 56.8ms 55.3ms // 50000 5026ms 54ms 1286ms 1298ms // 冒泡排序 function maopao(arr) { var arr1 = arr.slice(0); var len = arr1.length; for(var i = 0;i < len;i++){ for(var j = (i+1);j<len;j++){ if(arr1[i] > arr1[j]){ var tmp = arr1[i]; arr1[i] = arr1[j]; arr1[j] = tmp; } } } return arr1; } // console.time('maopao'); // var maopao_arr = maopao(arr1); // console.timeEnd('maopao'); // console.log(maopao_arr); // 快排 快速排序 //1、找基准(一般是以中间项为基准) //2、遍历数组,小于基准的放在left,大于基准的放在right //3、递归 function kuaipai(arr) { if(arr.length<=1){return arr;} var index = Math.floor(arr.length/2); var base_num = arr.splice(base_num,1)[0]; var l = []; var r = []; var len = arr.length; for(var i = 0; i < len;i++){ if(arr[i]<= base_num){ l.push(arr[i]); } else{ r.push(arr[i]); } } return kuaipai(l).concat( [base_num],kuaipai(r) ); } // console.time('kuaipai'); // var kuaipai_arr = kuaipai(arr1); // console.timeEnd('kuaipai'); // console.log(kuaipai_arr); // 插入排序 // 类似于斗地主整理牌时窝们人类所使用的算法:不断把牌抽出来,插入到已有牌中应处的位置 // 将n个元素的数列分为已有序和无序两个部分 // 将该数列的第一元素视为有序数列,后面都视为无序数列 // 将无序数列中的元素插入到有序数列的对应位置,插入前通过比大小的方式找到其在有序数列中的对应位置。 // 找位置的时候有两种方式找,就近找可以减少比较次数 function insertSort(arr){ var len = arr.length; for (var i = 1; i < len; i++) { //不断和前一个数比 if(arr[i] < arr[i-1] ){ var el = arr[i]; var ind; //找插入位置 look: for(var j = 0;j<len;j++){ if( el < arr[j]){ ind = j; break look; } } // 从j开始到原插入元素部分全部后移一位 for(var k = i;k>j;k--){ arr[k] = arr[k-1] } arr[ind] = el; } } return arr; } // console.log(arr1); // console.time('insertSort'); // var insert_arr = insertSort(arr1); // console.timeEnd('insertSort'); // console.log(insert_arr); function insertSort2(arr) { var len = arr.length; for (var i = 1; i < len; i++) { if(arr[i] < arr[i-1] ){ var el = arr[i]; arr[i] = arr[i-1]; var j = i-1; while( (j >= 0) && (el < arr[j]) ){ arr[j+1] = arr[j]; j--; } arr[j] = el; } } return arr; } // console.log(arr1); console.time('insertSort2'); var insert_arr2 = insertSort(arr1); console.timeEnd('insertSort2'); // console.log(insert_arr2);
paixu.js
'use strict'; // 排序算法、 var arr1 = ranArr2(1000); // 取5次的平均时间 // 比较 (个数) 冒泡 快速排序 插入排序 // 100 0.354ms 0.443ms 0.294ms // 1000 2.94ms 2.351ms 1.89ms 1.84ms // 10000 158.39ms 12.15ms 56.8ms 55.3ms // 50000 5026ms 54ms 1286ms 1298ms // 冒泡排序 function maopao(arr) { var arr1 = arr.slice(0); var len = arr1.length; for(var i = 0;i < len;i++){ for(var j = (i+1);j<len;j++){ if(arr1[i] > arr1[j]){ var tmp = arr1[i]; arr1[i] = arr1[j]; arr1[j] = tmp; } } } return arr1; } // console.time('maopao'); // var maopao_arr = maopao(arr1); // console.timeEnd('maopao'); // console.log(maopao_arr); // 快排 快速排序 //1、找基准(一般是以中间项为基准) //2、遍历数组,小于基准的放在left,大于基准的放在right //3、递归 function kuaipai(arr) { if(arr.length<=1){return arr;} var index = Math.floor(arr.length/2); var base_num = arr.splice(base_num,1)[0]; var l = []; var r = []; var len = arr.length; for(var i = 0; i < len;i++){ if(arr[i]<= base_num){ l.push(arr[i]); } else{ r.push(arr[i]); } } return kuaipai(l).concat( [base_num],kuaipai(r) ); } // console.time('kuaipai'); // var kuaipai_arr = kuaipai(arr1); // console.timeEnd('kuaipai'); // console.log(kuaipai_arr); // 插入排序 // 类似于斗地主整理牌时窝们人类所使用的算法:不断把牌抽出来,插入到已有牌中应处的位置 // 将n个元素的数列分为已有序和无序两个部分 // 将该数列的第一元素视为有序数列,后面都视为无序数列 // 将无序数列中的元素插入到有序数列的对应位置,插入前通过比大小的方式找到其在有序数列中的对应位置。 // 找位置的时候有两种方式找,就近找可以减少比较次数 function insertSort(arr){ var len = arr.length; for (var i = 1; i < len; i++) { //不断和前一个数比 if(arr[i] < arr[i-1] ){ var el = arr[i]; var ind; //找插入位置 look: for(var j = 0;j<len;j++){ if( el < arr[j]){ ind = j; break look; } } // 从j开始到原插入元素部分全部后移一位 for(var k = i;k>j;k--){ arr[k] = arr[k-1] } arr[ind] = el; } } return arr; } // console.log(arr1); // console.time('insertSort'); // var insert_arr = insertSort(arr1); // console.timeEnd('insertSort'); // console.log(insert_arr); function insertSort2(arr) { var len = arr.length; for (var i = 1; i < len; i++) { if(arr[i] < arr[i-1] ){ var el = arr[i]; arr[i] = arr[i-1]; var j = i-1; while( (j >= 0) && (el < arr[j]) ){ arr[j+1] = arr[j]; j--; } arr[j] = el; } } return arr; } // console.log(arr1); console.time('insertSort2'); var insert_arr2 = insertSort(arr1); console.timeEnd('insertSort2'); // console.log(insert_arr2); // 生成一个指定数量的不含重复数字的随机数组 // 同步递归回调版 function ranArr(n,callback) { var res = []; res = lack(res,n); ckRanArr(res,n,0,function (res) { return callback(res); }); } // 同步循环生成版 function ranArr2(n){ var arr = []; arr = lack(arr,n); var limit; if(n < 1000){ limit = 10*n; } else{ limit = n; } cl:for(var i = 0;i < limit;i++){ //console.log(i); var arr2 = quchong(arr); // 去重 if(arr2.length < n){ arr = lack(arr2,n); // 补量 } else{ break cl; } } return arr; } // 生成一个指定范围内(正整数 a到b)的随机数 function ranNum(a,b){ var n = Math.abs(a - b ); var base_n = a; if(a > b){ base_n = b; } var res = Math.floor(Math.random()*n) + base_n; return res; } // 返回去除重复项后的数组 function quchong(arr) { var arr2 = arr.slice(0); var arr2_len = arr2.length; var arr3 = []; for(var j = 0;j < arr2_len;j++){ // 重复项不进新数组 去重 (function (item,ind) { var flag = false; for(var k = (ind + 1);k < arr2_len; k++){ if(item == arr2[k]){ flag = true; } } if(!flag){ arr3.push(item); } }) (arr2[j],j); } return arr3; } // 补缺失的量并检查 function lack(arr,n) { // 去重后数量少了 补上 var arr_len = arr.length; if(arr_len < n){ var lack = n - arr_len; for(var j = 0; j < lack;j++){ arr.push( ranNum(0,100000000) ); } } return arr; } // 递归检查函数 count:重试次数 重试次数限制与生成数量相关 function ckRanArr(arr,n,count,callback){ var limit; if(n < 1000){ limit = 10*n; } if(n >= 1000){ limit = n; } if(count < limit){ count++; var arr2 = quchong(arr); // 去重 if(arr2.length < n ){ var arr3 = lack(arr2,n); // 补量 ckRanArr(arr3,n,count,callback); } else{ return callback(arr2); } } else{ return callback( quchong(arr) ); } } // console.time('a'); // var tmp = ranArr2(1000); // console.timeEnd('a'); // console.log( tmp ); // ranArr(10,function (res) { // console.log(res); // });