JS写的排序算法演示

来源:互联网 发布:fluent python mobi 编辑:程序博客网 时间:2024/04/28 09:50

看到网上有老外写的,就拿起自已之前完成的jmgraph画图组件也写了一个。
想了解jmgraph的请移步:https://github.com/jiamao/jmgraph

当前演示请查看:http://graph.jm47.com/example/sort.html

排序算法动画


<!doctype html><html><head><meta content="text/html; charset=UTF-8" http-equiv="content-type" /><title>排序算法演示</title><meta name="viewport" content="width=device-width,initial-scale=1"><script src="http://mat1.gtimg.com/www/mobi/js/zepto.min.js"></script><!--[if lt IE 9]><script type="text/javascript" src="../../jmgraph/src/lib/excanvas.js"></script><![endif]--><!--<script type="text/javascript" src="../src/jmgraph.debug.js"></script>--><script type="text/javascript" src="http://gqq.gtimg.com/fefeding/jmgraph/dist/jmGraph.min.js"></script></head><button id="btn_quick" href="#">快速排序</button><button id="btn_straightinsertion" href="#">直接插入排序</button><button id="btn_shell" href="#">希尔排序</button><button id="btn_simpleselection" href="#">简单选择排序</button><button id="btn_simpleselection2" href="#">二元选择排序</button><button id="btn_bubble" href="#">冒泡排序</button><body style="width:100%;"><div id="mycanvas" style="border:1px solid #ddd;width:100%;"></div></body><script type="text/javascript">//排序管理对象function jmSort() {//原始数组个数this.arrCount = 20;//原始数组this.source = [];var container = document.getElementById('mycanvas');this.canvasWidth = Math.min(600, document.getElementById('mycanvas').offsetWidth - 10);container.style.width = this.canvasWidth + 'px';this.canvasHeight = Math.min(450, window.innerHeight - 10);container.style.height = this.canvasHeight + 'px';this.graph = new jmGraph('mycanvas',this.canvasWidth,this.canvasHeight);this.rectStyle = {stroke:'rgb(173,173,209)',lineWidth:1,close:true,fill: 'rgb(8,209,54)'};this.disableStyle = {stroke:'rgba(173,173,209,0.8)',lineWidth:1,close:true,fill: 'rgba(88,196,113,0.5)'};//this.rectStyle.shadow = this.graph.createShadow(2,2,2,'rgb(39,40,34)');this.selectRectStyle = {stroke:'rgb(120,20,80)',lineWidth:1,zIndex: 100,close:true,fill: 'rgba(255,180,5,0.7)'};//this.selectRectStyle.shadow = this.graph.createShadow(4,4,6,'rgb(39,40,34)');//基准样式this.datumRectStyle = {stroke:'rgb(224,84,68)',lineWidth:2,close:true,zIndex: 50,lineType: 'dotted',fill: 'rgba(224,84,68,0.7)'};this.labelStyle = {stroke:'rgb(120,20,80)',textAlign: 'center',textBaseline: 'middle',font: '12px Arial',lineWidth:1};}//延迟数组循环jmSort.prototype.arrayTimeout = function(arr, fun, endfun, t, index, end) {index = index || 0;end = end || arr.length;var t = t || 200;var self = this;function intervalArr() {if(index >= end) {endfun && endfun(); return;}var r = fun(index, arr[index], function(){index ++;self.timeoutHandler = setTimeout(intervalArr, t);});if(r === false) {endfun && endfun(); return}}intervalArr();}//柱子移动动画jmSort.prototype.rectAnimate = function(rect, cb) {if(typeof index == 'function') {cb = index;index = 0;}if(!rect.length) {rect = [rect];}var tox = [];var offx = [];var pos = [];var count = rect.length;for(var i=0;i<count;i++) {pos[i] = rect[i].rect.position();//重新计算其x坐标tox[i] = this.xStep * rect[i].index + 10;offx[i] = (tox[i] - pos[i].x) / 20;}var self = this;function move() {var complete = 0;for(var i=0;i<count;i++) {pos[i].x += offx[i];if(offx[i] ==0 || (offx[i] > 0 && pos[i].x >= tox[i]) || (offx[i] < 0 && pos[i].x <= tox[i])) {pos[i].x = tox[i];complete++;}}self.graph.redraw();if(complete >= count) {cb && cb();}else {self.aniTimeoutHandler = setTimeout(move, 20);}}move();}//播放动画jmSort.prototype.play = function(frames, callback) {if(typeof frames == 'function') {callback = frames;frames = null;}frames = frames || this.frames;if(frames.length == 0) {callback && callback();return;}var f = frames.splice(0,1)[0];//取最早的一个var self = this;if(f.move && f.move.length) {//var count = 0;//for(var i=0;i<f.move.length;i++) {this.rectAnimate(f.move, function(){//count ++;//if(count >= f.move.length) {self.play(callback);//}});//}}else if(f.sels) {this.selectRect.apply(this, f.sels);this.play(callback);//setTimeout(function(){//self.play(callback);//}, 40);}else if(f.datum) {if(this.datumLine) {var start = this.datumLine.start();var end = this.datumLine.end();start.y = end.y = f.datum.rect.position().y;this.datumLine.visible = true;}this.play(callback);}else if(f.refresh) {this.refreshGraph(f.refresh);this.play(callback);}else {this.play(callback);}}//初始化排序条件,原始数组jmSort.prototype.init = function(){this.source = [];this.frames = [];var max = 100;var offy = this.canvasHeight - 20;this.graph.children.clear();//当前 x轴分布单位宽度this.xStep = (this.canvasWidth - 20) / this.arrCount;for(var i=0;i<this.arrCount;i++) {var v = {};v.value = Math.floor(Math.random() * max);v.height = v.value / max * offy;this.source.push(v);}//画基准线this.datumLine = this.graph.createLine({x:0,y:0},{x:this.canvasWidth,y:0},this.datumRectStyle);this.datumLine.visible = false;this.graph.children.add(this.datumLine);this.refreshGraph(this.source);}jmSort.prototype.reset = function() {if(this.timeoutHandler) clearTimeout(this.timeoutHandler);if(this.aniTimeoutHandler) clearTimeout(this.aniTimeoutHandler);if(this.datumLine) this.datumLine.visible = false;//this.refreshGraph();this.init();}//刷新画布jmSort.prototype.refreshGraph = function(arr) {arr = arr || this.source;//this.graph.children.clear();var offy = this.canvasHeight - 20;for(var i=0;i<arr.length;i++) {if(arr[i].rect) {var pos = arr[i].rect.position();pos.x = this.xStep * i + 10;}else {var pos = {};pos.x = this.xStep * i + 10;pos.y = offy - arr[i].height;arr[i].rect = this.graph.createShape('rect',{position:pos,width: 10, height: arr[i].height, style: this.rectStyle});var label = this.graph.createShape('label',{style:this.labelStyle,position:{x:0,y:arr[i].height},value:arr[i].value,width:10,height:20});arr[i].rect.children.add(label);this.graph.children.add(arr[i].rect);}//this.graph.children.add(arr[i].rect);}this.graph.redraw();}//选中某几个值,则加亮显示jmSort.prototype.selectRect = function(datum, sels, area) {var self = this;this.graph.children.each(function(i, rect) {if(!rect.is('jmRect')) return;if(sels && sels.indexOf(rect) > -1) {rect.style = self.selectRectStyle;}else if(datum && datum.indexOf(rect) > -1) {rect.style = self.datumRectStyle;}else if(area && area.indexOf(rect) > -1) {rect.style = self.rectStyle;}else {rect.style = self.disableStyle;}});this.graph.refresh();}//快速排序//取其中一个值,把小于此值的放到其左边,大于此值的放到其右边//如此递归jmSort.prototype.quickSort = function(arr, callback) {if(typeof arr == 'function') {callback = arr;arr = null;}arr = arr || this.source;var self = this;function sort(source, oldleft, oldrigth) {if(source.length <= 1) return source;//取一个值做为比较对象,这里直接取中间的值(任务一个都可)var mindex = Math.floor(source.length /2);var m = source[mindex];//基准值self.frames.push({datum: m});//选中当前区域var area = [];for(var i=0;i<source.length;i++) {area.push(source[i].rect);}self.frames.push({sels:[[m.rect],null, area]});var left = mindex>0?source.slice(0, mindex):[];var right = mindex>0&&mindex<source.length-1?source.slice(mindex+1):[];var middle = [m];var index = oldleft?oldleft.length:0;for(var i=0;i<source.length;i++) {var s = source[i];self.frames.push({sels:[[m.rect],[s.rect], area]});var f = {move:[]};var sindex = i;if(s.value < m.value) {if(i < mindex) continue;left.push(s);var rindex = right.indexOf(s);right.splice(rindex, 1);sindex = left.length - 1;f.move.push({rect: s.rect,index: sindex + index});var movearr = middle.concat(right);for(var j=0;j<rindex+middle.length;j++) {f.move.push({rect: movearr[j].rect,index: sindex + index + j + 1});}}else if(s.value > m.value) {if(i > mindex) continue;var lindex = left.indexOf(s);left.splice(lindex, 1);right.unshift(s);sindex = left.length + middle.length;f.move.push({rect: s.rect,index: sindex + index});var movearr = left.concat(middle);for(var j=lindex;j<movearr.length;j++) {f.move.push({rect: movearr[j].rect,index: index + j});}}else if(i != mindex) {if(i < mindex) {var lindex = left.indexOf(s);left.splice(lindex, 1);middle.unshift(s);sindex = left.length;f.move.push({rect: s.rect,index: sindex + index});for(var j=lindex;j<left.length;j++) {f.move.push({rect: left[j].rect,index: index + j});}}if(i > mindex) {var rindex = right.indexOf(s);right.splice(right.indexOf(s), 1);middle.push(s);sindex = left.length + middle.length - 1;f.move.push({rect: s.rect,index: sindex + index});for(var j=0;j<rindex;j++) {f.move.push({rect: right[j].rect,index: sindex + index + j + 1});}}}if(f.move.length) self.frames.push(f);}return sort(left, oldleft, middle.concat(right, oldrigth||[])).concat(middle, sort(right, (oldleft||[]).concat(left, middle)));}var result = sort(arr);this.play(function(){callback && callback(result);});return result;}//直接插入排序//将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表。即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。jmSort.prototype.straightInsertionSort = function(arr, dk, callback) {if(typeof arr == 'function') {callback = arr;arr= null;}if(typeof dk == 'function') {callback = dk;dk= 0;}arr = arr || this.source;dk = dk || 1;//拷贝一份var result = arr.slice(0);var self = this;for(var i=dk;i<result.length;i++) {var k = i;var j = k - dk;while(j>=0) {var v = result[k];var pre = result[j];this.frames.push({sels: [[v.rect], [pre.rect]]});if(v.value < pre.value) {result[j] = v;result[k] = pre;v.index = j;pre.index = k;this.frames.push({move: [{rect: pre.rect,index:k}, {rect:v.rect,index:j}]});k = j;j -= dk;}else {break;}}}callback && callback(result);return result;}//希尔排序//先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。jmSort.prototype.shellSort = function(arr, callback) {if(typeof arr == 'function') {callback = arr;arr = null;}arr = arr || this.source;var dk = Math.floor(arr.length / 2);var result = arr;while(dk >= 1) {result = this.straightInsertionSort(result, dk);dk = Math.floor(dk / 2);}this.play(function(){callback && callback(result);});return result;}//简单选择排序//在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换;然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素(最后一个数)比较为止。jmSort.prototype.simpleSelectionSort = function(arr, callback) {if(typeof arr == 'function') {callback = arr;arr = null;}arr = arr || this.source.slice(0);for(var i=0;i<arr.length-1;i++) {var min = arr[i];var minindex = i;for(var j=i+1;j<arr.length;j++) {if(min.value > arr[j].value) {min = arr[j];minindex = j;}//this.frames.push({sels:[[min.rect], [arr[j].rect]]});}if(minindex != i) {this.frames.push({sels:[[min.rect], [arr[i].rect]]});this.frames.push({move: [{rect: min.rect, index: i}, {rect: arr[i].rect, index: minindex}]});arr[minindex] = arr[i];arr[i] = min;}}this.play(function(){callback && callback(arr);});return arr;}//二元选择排序//简单选择排序,每趟循环只能确定一个元素排序后的定位。我们可以考虑改进为每趟循环确定两个元素(当前趟最大和最小记录)的位置,从而减少排序所需的循环次数。改进后对n个数据进行排序,最多只需进行[n/2]趟循环即可jmSort.prototype.selection2Sort = function(arr, callback) {if(typeof arr == 'function') {callback = arr;arr = null;}arr = arr || this.source.slice(0);var index = -1;var self = this;var end = Math.floor(arr.length / 2);for(var i=0;i<end;i++) {//取最小值和最大值var min = arr[i];var max = arr[i];var minindex = i;var maxindex = i;for(var j=i+1;j<arr.length-i;j++) {if(min.value > arr[j].value) {min = arr[j];minindex = j;}if(max.value <= arr[j].value) {max = arr[j];maxindex = j;}}var maxpos = j - 1;this.frames.push({sels:[[min.rect, arr[i].rect], [max.rect, arr[maxpos].rect]]});if(minindex != i) {this.frames.push({move: [{rect: min.rect, index: i}, {rect: arr[i].rect, index: minindex}]});arr[minindex] = arr[i];arr[i] = min;//如果最大值是当前起始值,则它被换到最小值位置上了//需要重新改变最大值的索引为找到的最小值的索引if(maxindex == i) {maxindex = minindex;}}if(maxindex != maxpos) {this.frames.push({move: [{rect: max.rect, index: maxpos}, {rect: arr[maxpos].rect, index: maxindex}]});arr[maxindex] = arr[maxpos];arr[maxpos] = min;}}this.play(function(){callback && callback(arr);});return arr;}//冒泡排序//在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。jmSort.prototype.bubbleSort = function(arr, callback) {if(typeof arr == 'function') {callback = arr;arr = null;}arr = arr || this.source.slice(0);var i = arr.length - 1;while(i > 0) {var pos = 0;for(var j=0;j<i;j++) {this.frames.push({sels: [[arr[j].rect],[arr[j+1].rect]]});if(arr[j].value > arr[j+1].value) {pos = j;var tmp=arr[j];arr[j]=arr[j+1];arr[j+1]=tmp;this.frames.push({move: [{rect: tmp.rect,index: arr.indexOf(tmp)},{rect: arr[j].rect,index: arr.indexOf(arr[j])}]});}}i=pos;}this.play(function(){callback && callback(arr);});}$(function(){//开始var sort = new jmSort();sort.init();sort.selection2Sort(function(ret){console.log(ret);});$('#btn_quick').click(function(){sort.reset();sort.quickSort(null,null,null,function(ret) {this.datumLine.visible = false;this.selectRect(ret);console.log(ret);});return false;});$('#btn_straightinsertion').click(function(){sort.reset();sort.straightInsertionSort(function(result){sort.play();console.log(result);});return false;});$('#btn_shell').click(function(){sort.reset();sort.shellSort();return false;});$('#btn_simpleselection').click(function(){sort.reset();sort.simpleSelectionSort();return false;});$('#btn_simpleselection2').click(function(){sort.reset();sort.selection2Sort();return false;});$('#btn_bubble').click(function(){sort.reset();sort.bubbleSort();return false;});});</script></html>




0 0