JavaScript排序算法动画演示效果的实现方法


Posted in Javascript onOctober 18, 2016

之前在知乎看到有人在问 自己写了一个冒泡排序算法如何用HTML,CSS,JavaScript展现出来排序过程。   感觉这个问题还挺有意思 。前些时间就来写了一个。这里记录一下实现过程。

基本的思想是把排序每一步的时候每个数据的值用DOM结构表达出来。

问题一:如何将JavaScript排序的一步步进程展现出来?

我试过的几种思路:

1.让JavaScript暂停下来,慢下来。

JavaScript排序是很快的,要我们肉眼能看到它的实现过程,我首先想到的是让排序慢下来。 排序的每一个循环都让它停300ms然后再继续进行。 怎么样才能停下来呢。查了一下JavaScript貌似没有sleep()这样的函数。暂停做不到,但是可以想办法让实现跟暂停差不多的效果。比如在循环里做一些无关的事情 。

首先尝试了让while(true)来一直执行一个空操作。执行一段时间再回到排序逻辑。代码大致是这样:

for (var i = 0; i < 3; i++) {
	document.writeln(i); //DOM操作 
	var now = new Date().getTime(); 
	while(new Date().getTime() - now < 3000){} 
}

慢是慢下来了。不过太耗资源,排序进行过程中dom并不会有任何改变,直到排序结束, DOM会变成排序好之后的样子。  但是如果设置断点一步步执行的时候 又可以看到一步步的排序变化。估计是因为这个操作太耗资源导致浏览器下达了一个DOM操作的命令但是一直腾不出资源来进行DOM操作。所以真正DOM操作的时候在js代码执行结束之后。
所以让JavaScript排序慢来来还是没有实现。

另一种让JavaScript暂停下来的思路:

写这个文章的时候又想到一种方法来让JavaScript停下来。 那就是AJAX的同步请求,以及超时操作。  也就是在要停下来的地方放一个AJAX请求,同步请求, 然后设置超时。超时的时间就是我们要暂停的时间。为了避免在到达超时请求之前服务 器就返回了我们的AJAX请求。可以在服务端运行类似 sleep()的程序 。从而保证AJAX不会返回。直接超时然后返回到我们的循环。不过这只是个设想。有兴趣的可以去尝试一下。

2.闭包和定时器。 这种思路不需要让排序过程慢下来。而是使用闭包缓存排序过程中数组的变化。然后使用setTimeout来确定展示每一个数组状态的顺序。在排序循环中放入类似下面的代码。

(function(){
  var theArr = arr.slice();//当前数组状态的备份
  setTimeout(function(){
    bubbleSortDom(theArr);//排序的DOM操作。
  },500*timeCount);
  timeCount++;//定时器的顺序。
})();

不过后来发现这样子写的话代码量会比较大,逻辑有修改的话要修改的地方会有点多。局限性很多,比如要实现排序动画加快或减慢操作几乎是很困难的。所以还要另想办法。

3.缓存排序中的数组状态。  

也就是在排序过程中。将数组的每一轮循环的状态保存到一个数组。然后再用这个数组依次将排序状态保存下来。 只需要在排序中加入一句就行。

this.pushHis(arr.slice(),i-1,j,k,temp);

这样就只需要一个setInterval()就可以了。并且可以很方便的实现动画的加快与减慢。逻辑也比较好理解 。

问题二:如何实现JavaScript排序动画的加快与减慢。

我们问题一使用的第三种方法。 得到一个保存了每一步排序状态的数组arr。  然后我们可以使用一个setInterval()定时器一步步展现排序状态。  如果要加快速度或减慢速度。就clearInterval(),修改定时器的执行间隔,重新setInterval(),从前一个定时器执行到数组中的位置开始执行。

问题三:对于使用递归实现的数组怎么办? 不是在原数组上进行操作的怎么办?

使用递归实现的排序。 可能并没有在一个数组上进行操作,只是最后返回一个排序好的数组出来。那么我们要如何获得排序中的数组的完整状态呢。

比如快速排序。

最开始不考虑动画,我的实现是这样的:

function quickSort(arr){
var len = arr.length,leftArr=[],rightArr=[],tag;
if(len<2){
return arr;
}
tag = arr[0];
for(i=1;i<len;i++){
if(arr[i]<=tag){
leftArr.push(arr[i])
}else{
rightArr.push(arr[i]);
}
}
return quickSort(leftArr).concat(tag,quickSort(rightArr));
}

然后为了考虑动画,我改写了它的逻辑,让它在同一个数组上进行了实现。 其实是在递归的时候传入了当前的的子数组在原数组中的起始位置。从而在原数组上进行了操作。

用了两种方法来实现方式。在排序逻辑上略有不同。

第一种是先跟远处的对比。遇到比自己小的放到自己前面去。循环序号+1。比自己大的放到当前排序子数组的最后面去,循环序号不变。直到排列完成。 
这种方法的缺点是即使是一个有序数组。它也会重新排。

第二种方法是 除了标记位,再设置一个对比位。 遇到比自己小的,放到前面去,标记位的位置+1,标记位与对比位之间所有的往后面移动一个位置。
遇到比自己大的。标记位不变,对比位+1。
这种方法的缺点是对数组进行的操作太多。优点是对有序数组不会再排。

方式一:

function quickSort(arr,a,b,qArr){

var len = arr.length,leftArr=[],rightArr=[],tag,i,k,len_l,len_r,lb,ra,temp;
if(a == undefined && b == undefined){
a = 0; b= arr.length-1;//初始化起始位置。
}
if(qArr == undefined){
qArr = arr.slice();
}

if((len == 2 && arr[0] == arr[1])||len<2){
return arr;
}

tag = qArr[a];
for (i = 1; i < len;) {
if(qArr[a+i]<=tag){
leftArr.push(qArr[a+i]);
qArr[a+i-1] = qArr[a+i];
qArr[a+i] = tag;
k = a+i;
i++;
}else{
if(leftArr.length+rightArr.length == len-1){
break;
}
temp = qArr[a+i];
qArr[a+i] = qArr[b-rightArr.length];
qArr[b-rightArr.length] = temp;
rightArr.push(temp);
k = a+i-1;
}
this.pushHis(qArr.slice(),a,b,k);
}

len_l = leftArr.length;
len_r = rightArr.length;
if(len_l== 0){
lb = a;
}else{
lb = a+len_l -1;
this.sort(leftArr,a,lb,qArr);
}

if(len_r == 0){
ra = b;
}else{
ra = b + 1 - len_r;
this.sort(rightArr,ra,b,qArr)
}
return qArr
}

方式二:

function quickSort2(arr,a,b,qArr){ 
  var len = arr.length,leftArr=[],rightArr=[],tag,i,j,k,temp,len_l,len_r,lb,ra; 
  if(a == undefined && b == undefined){ 
    a = 0; b= arr.length-1;//初始化起始位置。 
  } 
  if(qArr == undefined){ 
    qArr = arr.slice(); 
  } 
  if(len<2){ 
    return arr; 
  } 
  if(len == 2 && arr[0] == arr[1]){ 
    return arr; 
  } 
  tag = qArr[a]; 
  for (i = 1,k = 0; i < len;) { 
    if(qArr[a+i]>=tag){ 
      rightArr.push(qArr[a+i]); 
      i++; 
    }else{ 
      temp = qArr[a+i]; 
      for(j = a+i;j>a+k;j--){ 
        qArr[j] = qArr[j-1]; 
        // this.pushHis(qArr.slice(),a,b,a+k); 
      } 
      qArr[a+k] = temp; 
      leftArr.push(temp); 
      k++; 
      i++; 
    } 
    this.pushHis(qArr.slice(),a,b,a+k,i-1); 
  } 
  len_l = leftArr.length; 
  len_r = rightArr.length; 
  if(len_l== 0){ 
    lb = a; 
  }else{ 
    lb = a+len_l -1; 
    this.sort(leftArr,a,lb,qArr); 
  } 
  if(len_r == 0){ 
    ra = b; 
  }else{ 
    ra = b + 1 - len_r; 
    this.sort(rightArr,ra,b,qArr) 
  } 
  return qArr; 
}

具体的不同下面会有动画演示。

问题四:动画的流畅。

排序动画的DOM操作是很多的很快的。这里我做的优化只是让每一个排序步骤只涉及一个DOM操作。  全部由JavaScript拼接好,一次替换。类似下面的代码。

效果图:

JavaScript排序算法动画演示效果的实现方法

主要实现了:

冒泡排序JavaScript动画演示
插入排序JavaScript动画演示
选择排序JavaScript动画演示
快速排序JavaScript动画演示
归并排序JavaScript动画演示
希尔排序JavaScript动画演示

以上就是小编为大家带来的JavaScript排序算法动画演示效果的实现方法全部内容了,希望大家多多支持三水点靠木~

Javascript 相关文章推荐
Js放到HTML文件中的哪个位置有什么区别
Aug 21 Javascript
什么是Node.js?Node.js详细介绍
Jun 01 Javascript
js 判断数据类型的几种方法
Jan 13 Javascript
Javascript中的 “&amp;” 和 “|” 详解
Feb 02 Javascript
微信小程序上传图片到服务器实例代码
Nov 07 Javascript
Bootstrap Fileinput 4.4.7文件上传实例详解
Jul 25 Javascript
bootstrap table实现合并单元格效果
Dec 24 Javascript
vue 项目接口管理的实现
Jan 17 Javascript
vue设计一个倒计时秒杀的组件详解
Apr 06 Javascript
微信小程序实现传递多个参数与事件处理
Aug 12 Javascript
Javascript实现鼠标点击冒泡特效
Dec 24 Javascript
iSlider手机端图片滑动切换插件使用详解
Dec 24 Javascript
浅谈js的异步执行
Oct 18 #Javascript
Jquery AJAX POST与GET之间的区别详细介绍
Oct 17 #Javascript
微信小程序 教程之模块化
Oct 17 #Javascript
微信小程序 教程之注册页面
Oct 17 #Javascript
微信小程序 教程之注册程序
Oct 17 #Javascript
微信小程序 教程之小程序配置
Oct 17 #Javascript
jQuery事件对象总结
Oct 17 #Javascript
You might like
PHP include_path设置技巧分享
2011/07/03 PHP
php去除换行符的方法小结(PHP_EOL变量的使用)
2013/02/16 PHP
Linux系统下PHP-FPM的安装和配置教程
2015/08/17 PHP
jquery不支持toggle()高(新)版本的问题解决
2016/09/24 PHP
javascript中parentNode,childNodes,children的应用详解
2013/12/17 Javascript
实例讲解JS中数组Array的操作方法
2014/05/09 Javascript
Bootstrap源码解读导航条(7)
2016/12/23 Javascript
简单实现IONIC购物车功能
2017/01/10 Javascript
详解jQuery事件
2017/01/13 Javascript
js实现自动图片轮播代码
2017/03/22 Javascript
js实现本地图片文件拖拽效果
2017/07/18 Javascript
React-Native做一个文本输入框组件的实现代码
2017/08/10 Javascript
Angular如何在应用初始化时运行代码详解
2018/06/11 Javascript
vue-resource请求实现http登录拦截或者路由拦截的方法
2018/07/11 Javascript
通过封装scroll.js 获取滚动条的值
2018/07/13 Javascript
浅谈微信JS-SDK 微信分享接口开发(介绍版)
2018/08/15 Javascript
[04:00]黄浦江畔,再会英雄——完美世界DOTA2 TI9应援视频
2019/07/31 DOTA
Python统计日志中每个IP出现次数的方法
2015/07/06 Python
Python首次安装后运行报错(0xc000007b)的解决方法
2016/10/18 Python
Python正则替换字符串函数re.sub用法示例
2017/01/19 Python
Python实现读写INI配置文件的方法示例
2018/06/09 Python
python语音识别实践之百度语音API
2018/08/30 Python
Python3 读、写Excel文件的操作方法
2018/10/20 Python
Python实现Mysql数据统计及numpy统计函数
2019/07/15 Python
css3实现简单的白云飘动背景特效
2020/10/28 HTML / CSS
哥伦比亚最大的网上商店:Linio哥伦比亚
2016/09/25 全球购物
美国领先的低折扣旅行网站:Hotwire
2019/01/19 全球购物
戴尔马来西亚官网:Dell Malaysia
2020/05/02 全球购物
环保倡议书100字
2014/05/15 职场文书
房屋租赁合同协议书范本
2014/10/19 职场文书
课堂打架检讨书200字
2014/11/21 职场文书
计生个人工作总结
2015/02/28 职场文书
钢铁是怎样炼成的读书笔记
2015/06/29 职场文书
2016年小学推普宣传周活动总结
2016/04/06 职场文书
Nginx 根据URL带的参数转发的实现
2021/04/01 Servers
go开发alertmanger实现钉钉报警
2021/07/16 Golang