zoukankan      html  css  js  c++  java
  • 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="100%;">
            <div id="mycanvas" style="border:1px solid #ddd;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, 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,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>
  • 相关阅读:
    给linux用户分配docker权限
    alpine安装docker
    linux开机自启动配置
    virtualbox vdi硬盘扩容
    树莓派更新软件源的脚本
    原生js选中下拉框中指定值
    linux环境tomcat开启远程调试
    Vue2 和 Yii2 进行前后端分离开发学习
    httpd.conf文件中找不到Deny from all这句,怎么配置多站点
    yii2.0 advanced 学习教程
  • 原文地址:https://www.cnblogs.com/jiamao/p/4679320.html
Copyright © 2011-2022 走看看