用JavaScript实现排序算法动画【第三期】选择排序

算法概述

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。

主要参数

平均时间复杂度 最好情况 最坏情况 空间复杂度 排序方式 稳定性
O(n²) O(n²) O(n²) O(1) In-place 不稳定

往期回顾

本次动画还是沿用了前面我们封装好的一些函数,唯一不同的地方就是排序算法不同。如果没有看过我前面文章的小伙伴,建议先去看一下往期的该系列博客。

用JavaScript实现排序算法动画【第一期】冒泡排序

用JavaScript实现排序算法动画【第二期】插入排序

公共的内容我这里就直接贴出代码,不再进行讲解。

#warp .active{
    background-color: #da4d66;
    color: #ffffff;
}
#warp .undetermined{
    background-color: green;
    color: #ffffff;
}
#warp .complete{
    background-color: #00bcd4;
    color: #ffffff;
}
var warp = document.getElementById('warp')
var point = []   //保存所有的节点
//创建dom类
let Dom = function(height, left){
    this.dom = null
    this.height = height
    this.bottom = 0
    this.left = left
    this.createDom()
}
Dom.prototype = {
    createDom: function(){     //创建节点
        var ele = document.createElement('div')
        ele.style.height = this.height + "%"
        ele.style.left = this.left
        ele.innerHTML = `<span>${this.height}</span>`
        warp.appendChild(ele)
        this.dom = ele
        return this  //返回this是为可以使用链式调用
    },
    addClass: function(name){      //添加样式类
        this.dom.classList.add(name)
        return this
    },
    removeClass: function(name){   //移除样式类
        this.dom.classList.remove(name)
        return this
    },
move(position,pixel){   //移动位置
    this.dom.style[position] = pixel
    this[position] = pixel
    return this
}
}
//交换数组中的两个位置
Array.prototype.arrExchange = function(p1, p2){
    let v =  this[p1]
    this[p1] = this[p2]
    this[p2] = v
    return this
}

过程分析

在实现动画前,还是先来分析一下排序的过程

let array = [75,55,83,33,94,49,40,28,42,37,68]
let len = array.length
let temp
for (let i = 1; i < len; i++) {
    temp = array[i]
    let j = i - 1
    while(array[j] > temp && j >= 0){
        array[ j + 1] = array[j]
        j--
    }
    array[j + 1] = temp   
}

细心的朋友可以注意到,选择排序的时间复杂度永远都是 O(n²)。对于一个随机的数组,无论它初始状态是什么顺序,即便是初始状态就排好了顺序。对于选择排序来说,它的每轮循环必须都要从头到尾遍历一遍,即使在过程中找到了更小的元素,但是无法确定的是后面是否还有更小的元素。

动画实现

这对于我们实现这个动画有什么好处呢,选择排序它与插入排序不同,我们是可以明确的知道在选择排序中,内层循环的次数。可以利用这一点来确定每轮外层循环应该设置的延迟时间是多少。老办法用一个time变量用来累加每次内层循环的时间。

let len = array.length
let minIndex,temp,time = 0
for (let i = 0; i < len - 1; i++) {
    setTimeout(() => {
        minIndex = i
        for (let j = i + 1; j < len; j++) {
            setTimeout(() => {
                if(array[j] < array[minIndex])
                    minIndex = j
            }, (j-i-1)*500);
        }
        array = array.arrExchange(i, minIndex)
    }, time);
    time += (len - i + 1)*500 + 200
}

起始时time为0,直接开始第一轮的循环,第二轮循环必须要在第一轮完成后开始,第一轮循环共涉及到 len 个元素,每进行一轮就会递减一个元素,就应为 (len - i)*500。可以看到上面是(len - i + 1)*500 + 200 ,由于最后一个元素比较完成后,要进行位置互换,互换时间我在这里也设置的为500ms,所以这里要加1,这里+200ms是为了使每轮之间稍微有点间隔的余地。凡是都要留条后路。

let len = array.length
let minIndex,temp 
for (let i = 0; i < len - 1; i++) {
    setTimeout(() => {
        minIndex = i
        operation.changeStyle(minIndex, 'undetermined')
        for (let j = i + 1; j < len; j++) {
            setTimeout(() => {
                operation.changeStyle(j, 'active')
                operation.changeStyle(minIndex, 'undetermined')
                if(array[j] < array[minIndex]){
                    minIndex = j
                }
            }, (j-i-1)*500);
        }
        setTimeout(() => {
            array = array.arrExchange(i, minIndex)   //数组中交换位置
            operation.changePosition(i, 'left', 50*(minIndex - i)   )   //视觉上交换位置
            operation.changePosition(minIndex, 'left', -(50*(minIndex - i)))
            point.arrExchange(i, minIndex)   //实际的dom节点交换,一定要与数组同步,否则会影响后面的效果
            point[i].addClass('complete')
        }, (len - i)*500);
    }, time);
    time += (len - i + 1)*500 + 200
}

与冒泡排序和插入排序的动画还有一点不同,选择排序在比较过程中只对节点颜色上进行改变,只有当每轮结束后才会进行交换位置。这里一定要注意节点交换位置的时间,在上面已经得出了时间,其实就是  (len - i)*500 。

在前面的博客讲到过,这里的位置交换仅仅是视觉上的交换,不要忘记动画交换后对真实的dom节点进行交换,使其与排序数组中的顺序一直,否则后面的动画效果会让你抓头。

关注公众号《前端筱园》,回复“算法动画”获取完整源码

个人网站:www.dzyong.top

发布了81 篇原创文章 · 获赞 104 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/DengZY926/article/details/105129638