JS写的排序算法演示
看到网上有老外写的,就拿起自已之前完成的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="../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>
JS写的排序算法演示的更多相关文章
- GDI+学习笔记(九)带插件的排序算法演示器(MFC中的GDI+实例)
带插件的排序算法演示器 请尊重本人的工作成果,转载请留言.并说明转载地址,谢谢. 地址例如以下: http://blog.csdn.net/fukainankai/article/details/27 ...
- 链表插入和删除,判断链表是否为空,求链表长度算法的,链表排序算法演示——C语言描述
关于数据结构等的学习,以及学习算法的感想感悟,听了郝斌老师的数据结构课程,其中他也提到了学习数据结构的或者算法的一些个人见解,我觉的很好,对我的帮助也是很大,算法本就是令人头疼的问题,因为自己并没有学 ...
- [ 转载 ] js十大排序算法:冒泡排序
js十大排序算法:冒泡排序 http://www.cnblogs.com/beli/p/6297741.html
- js 十大排序算法 All In One
js 十大排序算法 All In One 快速排序 归并排序 选择排序 插入排序 冒泡排序 希尔排序 桶排序 堆排序(二叉树排序) 基数排序 计数排序 堆排序(二叉树排序) https://www.c ...
- JS十种经典排序算法,纯动画演示,学会了怼死面试官!
十种常见排序算法可以分为两大类: 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序. 线性时间非比较类排序:不通过比较来决定 ...
- JS中常见排序算法详解
本文将详细介绍在JavaScript中算法的用法,配合动图生动形象的让你以最快的方法学习算法的原理以及在需求场景中的用途. 有句话怎么说来着: 雷锋推倒雷峰塔,Java implements Java ...
- 使用vue实现排序算法演示动画
缘起 最近做的一个小需求涉及到排序,界面如下所示: 因为项目是使用vue的,所以实现方式很简单,视图部分不用管,本质上就是操作数组,代码如下: { // 上移 moveUp (i) { // 把位置i ...
- JS家的排序算法
由于浏览器的原生支持(无需安装任何插件),用JS来学习数据结构和算法也许比c更加便捷些.因为只需一个浏览器就能啪啪啪的调试了.比如下图我学习归并排序算法时,只看代码感觉怎么都理解不了,但是结合chro ...
- Canvas制作排序算法演示动画
tips: 形象化演示排序算法可以让初学者快速理解,比较好的例子:jun-lu的SortAnimate,旧金山大学的David Galles教授的算法演示课件.最近在看canvas,试着用js+can ...
随机推荐
- Nginx+tomcat负载均衡时静态页面报404
百度到的问题解决BLOG http://os.51cto.com/art/201204/326843.htm nginx+2台tomcat负载均衡,应用程序已部署,单独访问tomcat时,可以访问到所 ...
- NOIp蒟蒻的爆零记——HA-0132
考前: 从十一月开始的听课集训,连考六场:考前的最后两天写(da)着(zhe)各种各样的奇(C)葩(S)模板:一周的疯狂,已经过去: 考前的一晚:第二批高二的六个人聚在一起(还有滑稽大师),愉快的玩( ...
- 基于AWS的云服务架构最佳实践
ZZ from: http://blog.csdn.net/wireless_com/article/details/43305701 近年来,对于打造高度可扩展的应用程序,软件架构师们挖掘了若干相关 ...
- mysql 主从不同步
今天发现Mysql的主从数据库没有同步 先上Master库: mysql>show processlist; 查看下进程是否Sleep太多.发现很正常. show master status; ...
- 自动化-Appium
1.手把手教你 Android 标准 APP 的四大自动化测试法宝:https://testerhome.com/topics/5846 2.中文 Appium API 文档:https://test ...
- [11]APUE:(文件)记录锁
[a] 概念 建议锁:在遵循相同记录锁规则的进程间生效,通常用于保证某个程序自身多个进程间的数据一致性 强制锁:意在保证所有进程间的数据一致性,但不一定有效:如不能应对先 unlink 后建立同名副本 ...
- json改造优化无刷新分页
index.html dd
- zend studio常用快捷键
1.提示符助手快捷键 alt+/ 你可以自定义 window->keys->Content assist->Binding 2.复制当前行 alt+ctrl+下 3.删除 ctrl+ ...
- 不支持C++11 decltype的噩耗
前言:因为公司现在使用vs2008,所以很多c++11的新特性还未能使用,导致写了很多冤枉代码. 最初引擎的数学库非常简单,使用起来也不方便,例如: float FastLerp(const floa ...
- hdoj 2039 三角形
Problem Description 给定三条边,请你判断一下能不能组成一个三角形. Input 输入数据第一行包含一个数M,接下有M行,每行一个实例,包含三个正数A,B,C.其中A,B,C & ...