js 实现排序动画

前言:排序算是编程的一项基础技能,但是排序的过程并不直观,在新手入门的时候可能会在理解上产生一定的阻碍,所以本文将通过 js 来实现一些简单的排序,将整个排序的过程可视化出来,让排序知识更加通俗易懂。

重点知识

  • setInterval , 按指定周期计算函数(重复计算)
  • setTimeout, 指定时间后计算函数(计算一次)

冒泡排序

原理: 通过比较相邻元素的大小,元素值大的进行往后挪。

由于我们要使用 setInterval 来实现循环模拟,所以在函数开始的位置得事先设置定时器,在排序完成之后清除定时器。

为了使排序的动画更加显著,当前正在比较的两个元素设置为活跃状态即外边框为红色。具体设置的代码如下:

function setCss(){
        $mylist.removeClass('active');
        // 首先将之前比较的元素设置为不活跃状态
        $($mylist[current]).addClass("active");
        $($mylist[next]).addClass("active");
    }

然后就是如何实现两个元素的交换动画,在这里引用Github中他人实现交换代码。

传送门:https://github.com/tejanium/jquery.swap

接下来就是一步一步的进行比较,当比较到最后一个元素时,将当前元素置 0,下一个元素置 1。 具体代码如下:

        timer = setInterval(function(){
            if(times < count-1){
                finished = exchange();
                if(!finished){
                    current++;
                    next++;
                    if(current == count-times-1){
                        times++;
                        current = 0;
                        next = 1;
                        drawProcess();
                    }
                    setCss();
                }

            }
            else{
                clearInterval(timer);
                $mylist.removeClass('active');
            }
        }, 1000)
bubbleSort.gif

选择排序

原理:在每一趟排序中,选择出最大的元素,然后将这个元素放置在未排好序元素的末尾。

比较连个元素的大小时,先获取元素的文本,再将文本转化为整型,即可进行比较。具体实现如下:

function compare(){
        $mylist = $("#unorder li")
        var cur_val = parseInt($($mylist[current]).text());
        var max_val = parseInt($($mylist[max_pos]).text());
        if(cur_val > max_val){
            return true;
        }
        return false;
    }

关键步骤

首先假定最大元素在首位,依次将其后无序的元素与其进行比较,如果当前元素大于最大元素值,则更新最大元素值的位置,直到到最后一个元素,进行交换。之后,更新最大元素的位置为 0。

代码如下

    function start(){
        setCss();
        timer = setInterval(function(){
            if(times > 0){
                var comp = compare();
                if(comp){
                    max_pos = current;
                    current++;
                }
                else{
                    current++;
                }
                if(current == times+1){
                    exchange();
                    times --;
                    current = 1;
                    max_pos = 0;
                    setTimeout(drawProcess, 1000);
                }
                setCss();
            }
            else{
                $mylist.removeClass('max');
                $mylist.removeClass('active');
                clearInterval(timer);
            }
        }, 1000)
    }
selectSort.gif

插入排序

原理:与玩扑克牌的原理一致,每次找准每个元素的位置,然后插入进去。

由于插入效果代码并没有在网上找到,于是便根据上诉交换的效果的代码,自己依葫芦画瓢实现了一个。但是一个缺点就是没有做到很好的封装性,无法适用于所有情况,具体如下:

(function ($){
    $.fn.insert = function(a, b){
        t = this;
        if(t.length >= 1 && typeof(a) === "number" && a <= t.length){

            if(a == 0){
                _insert(t[0], b, true);
            }
            else{
                _insert(t[a-1], b, false);
            }
            
            return t;
        }
        else if(t.length === 0){
            b_clone = $(b).clone().css("opacity", 0);
            $("#order").prepend(b_clone);
            var first = $("#order li");
            first.insert(0, b);
            b_clone.remove();
        }
    };

    function _insert(a, b, option){
        var from = $(b),
            dest = $(a),
            from_pos = from.offset(),
            dest_pos= from.offset(),
            from_clone = from.clone(),
            dest_clone = dest.clone();

        from.css("opacity", 0);
        from_clone.insertAfter(from).css({position: "absolute", width: from.outerWidth(), height: from.outerHeight()}).offset(from_pos).css("z-index", "999");

        if(option){
            dest_clone.insertBefore(dest).css("opacity", 0);
        }
        else{
            dest_clone.insertAfter(dest).css("opacity", 0);
        }

        var route_from_vertical = dest_clone.offset().top - from_clone.offset().top;
        var route_from_horizontal = dest_clone.offset().left - from_clone.offset().left;

        from_clone.animate({
            top: "+=" + route_from_vertical + "px",
            left: "+=" + route_from_horizontal + "px",
            },
            "slow",
            function(){
                from.insertBefore(dest_clone).css("opacity", 1);
                $(this).remove();
                dest_clone.remove();
        });

        return from;
    }

})(jQuery);

关键步骤

将每个元素与排好序的元素进行比较,找准元素的位置进行插入。第一元素无需进行比较,直接进行插入。代码如下:

    function start(){

        mylist = $("#unorder li");
        var firstElement = mylist[0];
        sortList = $("#order li");
        sortList.insert(0, firstElement);

        setCSS();

        timer = setInterval(function(){

            mylist = $("#unorder li");

            firstElement = mylist[0];
            sortList = $("#order li");

            var comp = compare(firstElement, sortList[cur_pos]);
            if(comp){
                cur_pos++;
                if(cur_pos === sortList.length){
                    sortList.insert(cur_pos, firstElement);
                    cur_pos = 0;
                }
            }
            else{
                sortList.insert(cur_pos, firstElement);
                cur_pos = 0;
            }
            setCSS();

            sortList = $("#order li");
            if(sortList.length === count){
                clearInterval(timer);
            }

        }, 1000);
    }
insertSort.gif

最后做成的网页如下图所示,可选项是三种排序方法,每一次刷新网页都会随机生成一个数组。

存在的bug

上诉效果演示是使用了bootstrap作为页面显示的前端框架,而不用框架的话,效果会更加生动,元素首先会变大,然后在缩小,具体如下:

我不知道为何用了bootstrap之后,元素的效果是没有变大,而是直接进行了交换?在控制台惊醒调试的时候发现了这个。

这个是在用了bootstrap之后的调试结果:

这个是没有用bootstrap之后调试的结果:

我不明白css都是用的同样的代码,为什么两者的宽度会是截然不同的?

潜在的bug,一直未能解决?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,384评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 三级是一箱10盒,拿来进行销售,三级是投入最少,利润当然也是最低的了。 按照投资收益的比例是不低的: 1箱10盒,...
    幸福花园阅读 482评论 0 0
  • 最近我的体重终于在历时5年的增长后回调了,而且我有信心它会进一步回调,回到增长起点也完全有可能。体会减肥的这个过程...
    崔崔陶子阅读 545评论 1 4
  • 今天喝了许多茶,毫无睡意。感觉不写些什么都对不起自己。 罗老师来漳州开奥赛的讲座,后来约我出来。今天认识了陈教研员...
    小花孟阅读 228评论 0 0