mirror of
				https://gitee.com/coder-xiaomo/algorithm-visualization
				synced 2025-11-04 15:43:10 +08:00 
			
		
		
		
	添加插入排序算法;添加弹出弹回动画;动画参数放入全局settings变量中;添加debugMode全局变量
This commit is contained in:
		@@ -10,6 +10,7 @@ function getSortClassList() {
 | 
			
		||||
        QuickSort,
 | 
			
		||||
        BubbleSort,
 | 
			
		||||
        SelectionSort,
 | 
			
		||||
        InsertionSort
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -267,3 +268,64 @@ class SelectionSort extends Sort {
 | 
			
		||||
        return array
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 插入排序算法 Insertion Sort  v0.1.0
 | 
			
		||||
 *
 | 
			
		||||
 * @author  coder-xiaomo
 | 
			
		||||
 * @date    2022-05-18
 | 
			
		||||
 */
 | 
			
		||||
class InsertionSort extends Sort {
 | 
			
		||||
 | 
			
		||||
    info() {
 | 
			
		||||
        return {
 | 
			
		||||
            name: "插入排序算法"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
        将第一个元素标记为已排序
 | 
			
		||||
        对于每一个未排序的元素 X
 | 
			
		||||
            “提取” 元素 X
 | 
			
		||||
            i = 最后排序过元素的索引 到 0 的遍历
 | 
			
		||||
                如果当前元素 j > X
 | 
			
		||||
                    将排序过的元素向右移一格
 | 
			
		||||
            跳出循环并在此插入 X
 | 
			
		||||
    */
 | 
			
		||||
    sort(array) {
 | 
			
		||||
        if (array.length == 0)
 | 
			
		||||
            return array
 | 
			
		||||
        console.log(array)
 | 
			
		||||
        for (let i = 1; i < array.length; i++) {
 | 
			
		||||
            let X = array[i]
 | 
			
		||||
            let j = i - 1
 | 
			
		||||
            while (array[j] >= 0 && array[j] > X) {
 | 
			
		||||
                array[j + 1] = array[j]
 | 
			
		||||
                j--
 | 
			
		||||
            }
 | 
			
		||||
            array[j + 1] = X
 | 
			
		||||
        }
 | 
			
		||||
        return array
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sortWithAnimation(customAttr, array) {
 | 
			
		||||
        if (array.length == 0)
 | 
			
		||||
            return array
 | 
			
		||||
        console.log(array)
 | 
			
		||||
        for (let i = 1; i < array.length; i++) {
 | 
			
		||||
            let X = array[i]
 | 
			
		||||
            animation.popupLinkedListItems(customAttr.id, i, {})
 | 
			
		||||
            let j = i - 1
 | 
			
		||||
            while (array[j] >= 0 && array[j] > X) {
 | 
			
		||||
                array[j + 1] = array[j]
 | 
			
		||||
                animation.exchangeLinkedListItems(customAttr.id, j + 1, j)
 | 
			
		||||
                j--
 | 
			
		||||
            }
 | 
			
		||||
            array[j + 1] = X
 | 
			
		||||
            animation.popupLinkedListItems(customAttr.id, j + 1, { popBack: true })
 | 
			
		||||
        }
 | 
			
		||||
        return array
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,7 @@ var sortAlgorithm = {
 | 
			
		||||
    quicksort: new QuickSort(animation),
 | 
			
		||||
    bubblesort: new BubbleSort(animation),
 | 
			
		||||
    selectionSort: new SelectionSort(animation),
 | 
			
		||||
    insertionSort: new InsertionSort(animation),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 遍历每一种算法
 | 
			
		||||
@@ -51,7 +52,7 @@ Object.values(sortAlgorithm).forEach(sortAlgo => {
 | 
			
		||||
        var input = JSON.parse(JSON.stringify(element))
 | 
			
		||||
        // 进行排序
 | 
			
		||||
        var result = sortAlgo.sort(input)
 | 
			
		||||
        console.log(input, result)
 | 
			
		||||
        console.log("before", element, "after", result)
 | 
			
		||||
        // 与结果进行对比,判断是否正确
 | 
			
		||||
        if (data.indexOf(element) > -1) {
 | 
			
		||||
            var rightSortResult = check[data.indexOf(element)];
 | 
			
		||||
 
 | 
			
		||||
@@ -202,6 +202,16 @@ class Shape {
 | 
			
		||||
                .attr("height", oneUnit)
 | 
			
		||||
                .attr("fill", settings.colorMap["text"])
 | 
			
		||||
 | 
			
		||||
            // 调试用
 | 
			
		||||
            if (settings.debugMode)
 | 
			
		||||
                _g.append("svg:text")
 | 
			
		||||
                    .text(i)
 | 
			
		||||
                    .attr("x", i * oneUnit)
 | 
			
		||||
                    .attr("y", oneUnit)
 | 
			
		||||
                    .attr("width", oneUnit)
 | 
			
		||||
                    .attr("height", oneUnit)
 | 
			
		||||
                    .attr("fill", "black")
 | 
			
		||||
 | 
			
		||||
            // console.log(text.node().getBBox())
 | 
			
		||||
            // console.log(text.node().getBoundingClientRect())
 | 
			
		||||
        }
 | 
			
		||||
@@ -272,17 +282,12 @@ class VectorAnimation {
 | 
			
		||||
        var deltaX = customAttr.oneUnit * (fromIndex - toIndex);
 | 
			
		||||
        var deltaY = customAttr.oneUnit * 1.08
 | 
			
		||||
 | 
			
		||||
        var animateSettings = {
 | 
			
		||||
            duration: 0.2,
 | 
			
		||||
            ease: "sine.inOut",
 | 
			
		||||
            delay: 0,
 | 
			
		||||
            yoyo: true,
 | 
			
		||||
        }
 | 
			
		||||
        var animateSettings = this.workSpace.settings.animation.getConf()
 | 
			
		||||
 | 
			
		||||
        // 如果是相邻的两个元素交换,或者要交换的两个元素是同一个元素
 | 
			
		||||
        if (Math.abs(fromIndex - toIndex) <= 1) {
 | 
			
		||||
            deltaY /= 2
 | 
			
		||||
            animateSettings.duration = 0.25
 | 
			
		||||
            animateSettings.duration *= 0.6
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var that = this
 | 
			
		||||
@@ -333,13 +338,6 @@ class VectorAnimation {
 | 
			
		||||
        customAttr.gsapTimeline.add(timeline)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 比较数组元素
 | 
			
		||||
    compareLinkedListItems(id, index1, index2) {
 | 
			
		||||
        this.highlightLinkedListItems(id, [index1, index2], function () {
 | 
			
		||||
            consoleLog(`比较索引为 ${index1} 和 ${index2} 的两个元素`)
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 高亮数组元素
 | 
			
		||||
    highlightLinkedListItems(id, indexList, onStartCallback) {
 | 
			
		||||
        let linkedList = document.getElementById(id)
 | 
			
		||||
@@ -356,12 +354,7 @@ class VectorAnimation {
 | 
			
		||||
            hightlightElementList_fill.push(gList[index].childNodes[0])
 | 
			
		||||
            hightlightElementList_text.push(gList[index].childNodes[1])
 | 
			
		||||
        }
 | 
			
		||||
        var animateSettings = {
 | 
			
		||||
            duration: 0.2,
 | 
			
		||||
            ease: "sine.inOut",
 | 
			
		||||
            delay: 0,
 | 
			
		||||
            yoyo: true,
 | 
			
		||||
        }
 | 
			
		||||
        var animateSettings = this.workSpace.settings.animation.getConf()
 | 
			
		||||
 | 
			
		||||
        let timeline = gsap.timeline({
 | 
			
		||||
            onStart: function () {
 | 
			
		||||
@@ -371,7 +364,7 @@ class VectorAnimation {
 | 
			
		||||
                    onStartCallback()
 | 
			
		||||
            },
 | 
			
		||||
            onComplete: function () {
 | 
			
		||||
                console.log("hightlight done")
 | 
			
		||||
                console.log("animation done (hightlight)")
 | 
			
		||||
            }
 | 
			
		||||
        }).add([
 | 
			
		||||
            gsap.to(hightlightElementList_fill, { ...animateSettings, fill: settings.colorMap["fill_focus"] }),
 | 
			
		||||
@@ -383,4 +376,92 @@ class VectorAnimation {
 | 
			
		||||
 | 
			
		||||
        customAttr.gsapTimeline.add(timeline)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 比较数组元素
 | 
			
		||||
    compareLinkedListItems(id, index1, index2) {
 | 
			
		||||
        this.highlightLinkedListItems(id, [index1, index2], function () {
 | 
			
		||||
            consoleLog(`比较索引为 ${index1} 和 ${index2} 的两个元素`)
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 弹出/弹回 数组元素
 | 
			
		||||
    popupLinkedListItems(id, index, { popBack = false }) {
 | 
			
		||||
        let linkedList = document.getElementById(id)
 | 
			
		||||
        let customAttr = linkedList.customAttr
 | 
			
		||||
        var gList = linkedList.childNodes
 | 
			
		||||
 | 
			
		||||
        var deltaY = customAttr.oneUnit * 1.08
 | 
			
		||||
        if (popBack) deltaY = 0
 | 
			
		||||
 | 
			
		||||
        let timeline = gsap.timeline({
 | 
			
		||||
            onStart: function () {
 | 
			
		||||
                if (typeof (onStartCallback) === "function")
 | 
			
		||||
                    onStartCallback()
 | 
			
		||||
            },
 | 
			
		||||
            onComplete: function () {
 | 
			
		||||
                console.log("animation done (popup)")
 | 
			
		||||
            }
 | 
			
		||||
        }).add([
 | 
			
		||||
            gsap.to(gList[index], { ...this.workSpace.settings.animation.getConf(), y: deltaY }),
 | 
			
		||||
        ])
 | 
			
		||||
 | 
			
		||||
        customAttr.gsapTimeline.add(timeline)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 交换相邻数组元素位置(仅在水平方向呼唤,垂直方向不做调整) 【fromIndex 是y方向上突出的元素】
 | 
			
		||||
    exchangeLinkedListItems(id, fromIndex, toIndex) {
 | 
			
		||||
        if (fromIndex < toIndex)
 | 
			
		||||
            [fromIndex, toIndex] = [toIndex, fromIndex]
 | 
			
		||||
 | 
			
		||||
        var settings = this.workSpace.settings
 | 
			
		||||
        let linkedList = document.getElementById(id)
 | 
			
		||||
        let customAttr = linkedList.customAttr
 | 
			
		||||
        // console.log(customAttr)
 | 
			
		||||
 | 
			
		||||
        var gList = linkedList.childNodes
 | 
			
		||||
 | 
			
		||||
        let from = gList[fromIndex]
 | 
			
		||||
        let to = gList[toIndex]
 | 
			
		||||
 | 
			
		||||
        var deltaX = customAttr.oneUnit * (fromIndex - toIndex);
 | 
			
		||||
 | 
			
		||||
        var deltaY = customAttr.oneUnit * 1.08 // 要跟 popupLinkedListItems 函数中的 deltaY 完全一致
 | 
			
		||||
        var animateSettings = settings.animation.getConf()
 | 
			
		||||
 | 
			
		||||
        var that = this
 | 
			
		||||
        let timeline = gsap.timeline({
 | 
			
		||||
            onStart: function () {
 | 
			
		||||
                displayCurrentArray(customAttr.nodes)
 | 
			
		||||
 | 
			
		||||
                consoleLog(`交换索引为 ${fromIndex} 和 ${toIndex} 的两个元素`)
 | 
			
		||||
            },
 | 
			
		||||
            onComplete: function () {
 | 
			
		||||
                // 交换DOM元素中的值
 | 
			
		||||
                that.swapElementInnerHTML(from.childNodes[1], to.childNodes[1])
 | 
			
		||||
 | 
			
		||||
                // 交换 node 列表中的值
 | 
			
		||||
                // console.log(customAttr.nodes)
 | 
			
		||||
                let tmp = customAttr.nodes[fromIndex]
 | 
			
		||||
                customAttr.nodes[fromIndex] = customAttr.nodes[toIndex]
 | 
			
		||||
                customAttr.nodes[toIndex] = tmp
 | 
			
		||||
 | 
			
		||||
                // console.log(customAttr.nodes)
 | 
			
		||||
                displayCurrentArray(customAttr.nodes)
 | 
			
		||||
 | 
			
		||||
                console.log("animation done (exchange)")
 | 
			
		||||
            }
 | 
			
		||||
        }).add([
 | 
			
		||||
            gsap.to(from.childNodes, { ...animateSettings, x: -deltaX }),
 | 
			
		||||
            gsap.to(to.childNodes, { ...animateSettings, x: deltaX }),
 | 
			
		||||
        ]).add([
 | 
			
		||||
            // 恢复到动画之前的状态
 | 
			
		||||
            gsap.to(from.childNodes, { ...animateSettings, duration: 0, x: 0 }),
 | 
			
		||||
            gsap.to(to.childNodes, { ...animateSettings, duration: 0, x: 0 }),
 | 
			
		||||
            // 由于两个元素一个突出,一个不突出,所以还要交换两个y
 | 
			
		||||
            gsap.to(from, { ...animateSettings, duration: 0, y: 0 }),
 | 
			
		||||
            gsap.to(to, { ...animateSettings, duration: 0, y: deltaY }),
 | 
			
		||||
        ])
 | 
			
		||||
 | 
			
		||||
        customAttr.gsapTimeline.add(timeline)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
// 全局变量
 | 
			
		||||
var settings = {
 | 
			
		||||
    container: d3.select("#container"),
 | 
			
		||||
    debugMode: false,
 | 
			
		||||
    outerSize: {    // 不带单位
 | 
			
		||||
        width: 800,
 | 
			
		||||
        height: 600
 | 
			
		||||
@@ -35,8 +36,14 @@ var settings = {
 | 
			
		||||
        "green": "#0f0",
 | 
			
		||||
    },
 | 
			
		||||
    animation: {
 | 
			
		||||
        duration: 2000,  // 不带单位,单位是毫秒
 | 
			
		||||
        easing: "ease-in-out"
 | 
			
		||||
        getConf: function () {  // gsap动画传入默认设置
 | 
			
		||||
            return {
 | 
			
		||||
                duration: 0.3,  // 单位是秒
 | 
			
		||||
                ease: "sine.inOut",
 | 
			
		||||
                delay: 0,
 | 
			
		||||
                yoyo: true,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    console: {
 | 
			
		||||
        maxLine: 30,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user