关于js写可视化排序中核心部分settimeout和闭包联合使用的问题

我在写js写可视化排序时 其他代码都没问题 ,冒泡核心写成下面这样程序可正常执行
图片说明
但是我想让它更好的可视化:循环的时候,如果遇到前一个大于后一个,两个div红色变灰色,等待1秒,这两个div交换,这两个div又变成红色,继续下一轮循环。
我仿照图片说明
写成下图
图片说明
写的时候我就感觉有问题(用50 40 30 20 测试确实有问题),但是我不知道怎么改。
求大神帮我把这小块核心改一下,并解答下我的问题,越详细越好。
求大神帮我把这小块核心改一下,并解答下我的问题,越详细越好。
求大神帮我把这小块核心改一下,并解答下我的问题,越详细越好。
主要的问题有:1.闭包不知道写对没有。
2.settimeout的延时设置1000j我感觉有问题
3.断点检测的时候settimeout好像要等所有的ij循环完了才执行,而我显然想让它遇到一对不合格的就执行一次。不知道怎么改
源代码如下:

 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>task2-5</title>
    <style type="text/css" >
        form{  width: 500px;  margin-left: auto;  margin-right: auto;  margin-top: 20px;  }
        div div{  width: 10px;background-color: red;display: inline-block;margin-right:1px;text-align: center;line-height: 30px;  }
        #show{  width: 500px;height: 300px;  margin-left: auto;  margin-right: auto; margin-top: 50px;}

    </style>
</head>
<body>
<form >
    <input  id="numInput" type="text" placeholder="请输入两位数的整数">
    <input  id="leftIn"  type="button" value="左侧入">
    <input  id="rightIn" type="button"  value="右侧入">
    <input  id="leftOut" type="button" value="左侧出">
    <input  id="rightOut" type="button" value="右侧出">
    <input  id="sort" type="button" value="冒泡排序">
    <input id="clear" type="button" value="清空">
</form>
<div id ="show">

</div>
<script type="text/javascript">
    //方案1:点击按钮行为增加或者删除相应的数组元素----》对数组元素遍历并改变相应的节点------》最后进行排序
    //方案2:先不设置数组  直接增减相应的节点----》待节点整体确定后,再输入数组,并进行排序
    //***************
    // ***选择方案2***
    //****************
    var show = document.getElementById("show");
    var txtinput =document.getElementById("numInput");
    var clrear = document.getElementById("clear");
    clrear.onclick = function () {
        show.innerHTML = null;
    };
    var rightOut = document.getElementById("rightOut");
    rightOut.onclick =function () {
        var divs = show.getElementsByTagName("div");
        if(divs.length==0){
            alert("还未插入数字");
        }else{
            show.removeChild(divs[divs.length-1]);
        }
    };
    var leftIn = document.getElementById("leftIn");
    leftIn.onclick = function () {
        if(verify(txtinput.value)){
            var numIn = parseInt(txtinput.value);
            //左输入:  创造节点 ---> 插入
            var addDiv = document.createElement("div");
            if(show.getElementsByTagName("div").length == 0){
            show.appendChild(addDiv);
                addDiv.style.height=numIn*2+"px";
            } else{
                show.insertBefore(addDiv,show.getElementsByTagName("div")[0] );
                addDiv.style.height=numIn*2+"px";
            }
        }
        };
    var rightIn = document.getElementById("rightIn");
    rightIn.onclick = function () {
        if (verify(txtinput.value)) {
            var numIn = parseInt(txtinput.value);
            //右输入:  创造节点 ---> 插入
            var addDiv = document.createElement("div");

            addDiv.style.height=numIn*2+"px";
            show.appendChild(addDiv);

        }
    };

        var leftOut = document.getElementById("leftOut");
        leftOut.onclick = function () {
            var divs = show.getElementsByTagName("div");
            if(divs.length==0){
                alert("还未插入数字");
            }else{
                show.removeChild(divs[0]);
            }
        };
        var sortButton =  document.getElementById("sort");
        sortButton.onclick = function () {
            var divs = show.getElementsByTagName("div");
            if(divs.length>60){
                alert("排序的元素个数不能超过60个,请删除多余的元素");
            }else{
                    sort(divs);
                }

        };
        //检验数字合法性    //存在一个问题  数字太大时溢出容器!!!  检验<100且不含其他字符
        function verify(str) {
            for (var i = 0; i < str.length; i++) {
                if ("1234567890".indexOf(str[i]) <= -1) {
                    alert("请输入100以下的整数");
                    return false;
                }
            }
            var numIn = parseInt(str);
            if (numIn >= 100) {
                alert("请输入两位数整数");
                return false;
            }
            if (numIn < 10) {
                alert("请输入两位数整数");
                return false;
            }
            return true;
        }
        //冒泡排序 从小到大
        function sort(arr) {
            var c = 0;
            for(var i = 0;i<arr.length;i++){
                for(var j=0;j<arr.length-1-i;j++){
                    if(parseInt(arr[j].style.height)>parseInt(arr[j+1].style.height)){
                        arr[j].style.backgroundColor = "#999";
                        arr[j+1].style.backgroundColor = "#999";
                        (function (j) {
                            setTimeout(function () {
                                c = arr[j].style.height;
                                arr[j].style.height = arr[j+1].style.height;
                                arr[j+1].style.height = c;
                                arr[j].style.backgroundColor = "red";
                                arr[j+1].style.backgroundColor = "red";
                            },j*1000);

                        }) (j)
                    }
                }
            }
        }
</script>
</body>
</html>

5个回答

冒泡排序需要先冒泡后再能继续下一轮的冒泡

计时器的话是延时的,2轮for其实都是参考第一次的高度,只会生成一次需要交换位置信息,而不是依赖上一轮冒泡的结果在生成交换位置的信息,所以排不正确

qflyalltime
小羊也疯狂 回复showbo: 你讲的非常对,昨天晚上纸上模拟了一遍,知道自己哪里错了,躺床上灵光一闪,其实不用重写函数,计时器的时间让它脱离j就行,采用一个独立参数time。不断time++模拟冒泡。传送门 :http://ask.csdn.net/questions/372843
大约 3 年之前 回复
showbo
支付宝加好友偷能量挖 回复小羊也疯狂: 计时器即使是延时0s执行,也是比for完执行的,也设置不了0s的,最小延时不同浏览器不一样,测试最小值为10ms左右。所以实际就是0- 1,1-2,2-3交换而且。 0-1后变为40 50 30 20【如果运气不好说不定i=1的延时早于i=0的执行,还会交换回去变为50 40 30 20,因为几乎同时执行的】 1-2后变为40 30 50 20【同样有可能出现0-1的情况】 2-3后变为40 30 20 50 只是执行了一轮冒泡而已。而冒泡是需要依次参考上一次的i冒泡再执行冒泡的,所以不能用for来并发启动n个计时器,这个只会参考初始化 的高度,而不是依次参考排序后的。你得将并发改为顺序执行,模拟for循环,参考上一次的排序。
大约 3 年之前 回复
showbo
支付宝加好友偷能量挖 回复小羊也疯狂: 你的计时器是晚于2轮for执行的,所以2轮for中的j那层循环都是参考初始化的高度,就拿50 40 30 20说明 for(var j=0;j<3;j++) 【生成3个计时器交换下面0,1(0延时执行) 1,2(1s延时执行) 2,3(2s延时执行)】 【另外3组的i=1~3对应的for参考的也是初始化高度50-》20,所以生成的计时器交换位置也是一样的,只是比上次少最后一组下标交换】 for(var j=0;j<2;j++)【0,1(0延时执行) 1,2(1s延时执行)】 for(var j=0;j<1;j++)【0,1(0延时执行)】 for(var j=0;j<0;j++)【//这轮不执行】
大约 3 年之前 回复
qflyalltime
小羊也疯狂 回复showbo: 计时器和冒泡的冲突能再讲细一点吗 没看懂......
大约 3 年之前 回复
showbo
支付宝加好友偷能量挖 和闭包没关系,主要是计时器和冒泡排序冲突了,不能直接for,需要顺序执行每次排序,大概写了个http://www.w3dev.cn/article/20170320/javascript-bubble-sort-dom-dynamic-graphic.aspx
大约 3 年之前 回复

把function sort(){.......}
换成下面的2个函数,但代码不是完美的,因为时间不均匀,所以显示的效果有快慢,数量越大,到后面,变化的越慢,可想办法消除时间误差,
如果感觉显示的太快,可以调节时间,进行调整
function sort(arr,i) {
var c = 0;
i=i==undefined?0:i;
if(i<arr.length){
sort1(arr,i,0);
setTimeout(function(){
i++;sort(arr,i)
},(i+1)*3000);
}
}

function sort1(arr,i,j) {
j=j==undefined?0:j;
if(j if(parseInt(arr[j].style.height)>parseInt(arr[j+1].style.height)){
arr[j].style.backgroundColor = "#999";
arr[j+1].style.backgroundColor = "#999";
setTimeout(function () {
if(parseInt(arr[j].style.height)>parseInt(arr[j+1].style.height)){
c = arr[j].style.height;
arr[j].style.height = arr[j+1].style.height;
arr[j+1].style.height = c;
arr[j].style.backgroundColor = "red";
arr[j+1].style.backgroundColor = "red";
}
},j*500);
}
setTimeout(function(){
j++;
sort1(arr,i,j)},(j+1)*1000);
}
}

function sort(arr,i) {
var c = 0;
i=i==undefined?0:i;
if(i<arr.length){
sort1(arr,i,0);
setTimeout(function(){
i++;
sort(arr,i);
},(i+1)*3000);
}
}

function sort1(arr,i,j) {
j=j==undefined?0:j;
if(j if(parseInt(arr[j].style.height)>parseInt(arr[j+1].style.height)){
arr[j].style.backgroundColor = "#999";
arr[j+1].style.backgroundColor = "#999";
setTimeout(function () {
if(parseInt(arr[j].style.height)>parseInt(arr[j+1].style.height)){
c = arr[j].style.height;
arr[j].style.height = arr[j+1].style.height;
arr[j+1].style.height = c;
arr[j].style.backgroundColor = "red";
arr[j+1].style.backgroundColor = "red";
}
},j*500);

    }
setTimeout(function(){
j++;
sort1(arr,i,j)},(j+1)*1000);
 }

}

发布上去,代码不全,可能CSDN过滤了一些字符
我截图上去

图片说明

if(j 这个地方错误,你 再找找其他地方还有没有,代码测试可用。

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问