From d30ceef3a79670f06ad98b5cd802ffa8253a63e2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98=E5=B0=8F=E5=A2=A8?=
<2291200076@qq.com>
Date: Mon, 8 Aug 2022 20:18:03 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=20=E5=BD=92=E5=B9=B6?=
=?UTF-8?q?=E6=8E=92=E5=BA=8F=E7=AE=97=E6=B3=95=EF=BC=88=E4=B8=8D=E8=A6=81?=
=?UTF-8?q?=E5=90=88=E5=88=86=E6=94=AF=EF=BC=89=EF=BC=9B=E5=8A=A8=E7=94=BB?=
=?UTF-8?q?=E5=B1=95=E7=A4=BA=E4=B8=8D=E5=A5=BD=E5=B1=95=E7=A4=BA=EF=BC=9B?=
=?UTF-8?q?=E5=BC=B9=E5=87=BA=E5=85=83=E7=B4=A0=E5=88=B0=E6=96=B0=E7=9A=84?=
=?UTF-8?q?=E6=95=B0=E7=BB=84=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81=E6=9C=AA?=
=?UTF-8?q?=E5=AE=8C=E6=88=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/assets/js/algorithm/sort.js | 1069 ++++++++++++------------
src/assets/js/algorithm/test.js | 145 ++--
src/assets/js/class.js | 1340 ++++++++++++++++---------------
src/index.html | 168 ++--
4 files changed, 1411 insertions(+), 1311 deletions(-)
diff --git a/src/assets/js/algorithm/sort.js b/src/assets/js/algorithm/sort.js
index 2d3cc1f..36e0a2e 100644
--- a/src/assets/js/algorithm/sort.js
+++ b/src/assets/js/algorithm/sort.js
@@ -1,509 +1,560 @@
-/**
- * 排序算法父类 Sort v0.1.0
- *
- * @author coder-xiaomo
- * @date 2022-05-16
- */
-
-function getSortClassList() {
- return [
- QuickSort,
- BubbleSort,
- SelectionSort,
- InsertionSort,
- MergeSort,
- RandomQuickSort,
- CountingSort,
- RadixSort,
- ]
-}
-
-class Sort {
- static animation = null
- constructor(animation) {
- this.animation = animation
- console.log(`初始化 ${this.info()['name']}`)
- }
-
- info() {
- return {
- name: "未命名算法",
- available: false
- }
- }
-
- sort(array) {
- console.log("this method was not implement.")
- return array
- }
-
- doSortWithAnimation(elementId) {
- let customAttr = document.getElementById(elementId).customAttr
- let array = JSON.parse(JSON.stringify(customAttr.nodes)) // 深拷贝一个数组
- console.log(customAttr, array)
- this.sortWithAnimation(customAttr, array)
- }
-
- sortWithAnimation(array) {
- console.log("this method was not implement.")
- return array
- }
-
- /**
- * 交换数组中的两个元素
- * @param {*} array 数组
- * @param {*} index1 元素1索引
- * @param {*} index2 元素2索引
- */
- swap(array, index1, index2) {
- if (index1 < 0 || index1 >= array.length)
- throw new Error("index1索引超限")
- if (index2 < 0 || index2 >= array.length)
- throw new Error("index2索引超限")
- if (index1 == index2)
- return
-
- let tmp = array[index1]
- array[index1] = array[index2]
- array[index2] = tmp
-
- // only for test
- // console.log(Object.keys(array))
- // console.log(array, index1, index2)
- }
- swapAnimation(id, index1, index2) {
- if (index1 == index2)
- return
- animation.swapLinkedListItems(id, [index1, index2])
- }
-}
-
-
-/**
- * 快速排序算法 Qucik Sort v0.1.0
- *
- * @author coder-xiaomo
- * @date 2022-05-16
- */
-class QuickSort extends Sort {
- /**
- * step
- *
- * 1. 首先设定一个分界值,通过该分界值将数组分成左右两部分
- * 2. 将大于或等于分界值的数据集中到数组右边,小于的集中到左边
- * 3. 左右两侧的数组分别重复步骤 2.
- * 4. 完成排序
- */
-
- info() {
- return {
- name: "快速排序算法",
- enName: "Quick Sort",
- available: true
- }
- }
-
- /*
- 每个(未排序)的部分
- 将第一个元素设为 pivot
- 存储索引 = pivot索引 +1
- 从 i=pivot指数 +1 到 最右索引 的遍历
- 如果 a[i] < a[pivot]
- 交换 (i, 存储索引); 存储索引++;
- 交换(pivot, 存储索引 - 1)
- */
- sort(array, left, right) {
- if (typeof (left) === "undefined") left = 0
- if (typeof (right) === "undefined") right = array.length - 1
-
- if (right <= left)
- return array // 递归出口
-
- const pivot = left // 第一个元素的索引
- let p = left + 1
- for (let i = left + 1; i <= right; i++) {
- if (array[i] < array[pivot]) {
- this.swap(array, i, p)
- p++
- }
- }
- this.swap(array, pivot, p - 1)
-
- // 左、右分别排序(索引超限在 sort 内部进行处理,此处无需判断)
- this.sort(array, pivot, p - 2)
- this.sort(array, p, right)
- return array
- }
-
- sortWithAnimation(customAttr, array, left, right) {
- if (typeof (left) === "undefined") left = 0
- if (typeof (right) === "undefined") right = array.length - 1
-
- if (right <= left)
- return array // 递归出口
-
- const pivot = left // 第一个元素的索引
- let p = left + 1
- for (let i = left + 1; i <= right; i++) {
- animation.compareLinkedListItems(customAttr.id, i, pivot)
- if (array[i] < array[pivot]) {
- this.swap(array, i, p)
- this.swapAnimation(customAttr.id, i, p)
- p++
- }
- }
- this.swap(array, pivot, p - 1)
- this.swapAnimation(customAttr.id, pivot, p - 1)
-
- // 左、右分别排序(索引超限在 sort 内部进行处理,此处无需判断)
- this.sortWithAnimation(customAttr, array, pivot, p - 2)
- this.sortWithAnimation(customAttr, array, p, right)
- return array
- }
-}
-
-
-/**
- * 冒泡排序算法 Bubble Sort v0.1.0
- *
- * @author coder-xiaomo
- * @date 2022-05-16
- */
-class BubbleSort extends Sort {
-
- info() {
- return {
- name: "冒泡排序算法",
- enName: "Bubble Sort",
- available: true
- }
- }
-
- /*
- 做
- swapped = false
- 从 i = 1 到 最后一个没有排序过元素的索引-1
- 如果 左边元素 > 右边元素
- 交换(左边元素,右边元素)
- swapped = true; ++swapCounter(交换计数器)
- while swapped
- */
- sort(array) {
- let sortTime = 0
- let swapped
- do {
- swapped = false
- for (let i = 1; i < array.length - sortTime; i++) {
- if (array[i - 1] > array[i]) {
- this.swap(array, i - 1, i)
- swapped = true
- }
- }
- sortTime++
- } while (swapped)
-
- return array
- }
-
- sortWithAnimation(customAttr, array) {
- let sortTime = 0
- let swapped
- do {
- swapped = false
- for (let i = 1; i < array.length - sortTime; i++) {
- animation.compareLinkedListItems(customAttr.id, i - 1, i)
- if (array[i - 1] > array[i]) {
- this.swap(array, i - 1, i)
- this.swapAnimation(customAttr.id, i - 1, i)
- swapped = true
- }
- }
- sortTime++
- } while (swapped)
-
- return array
- }
-}
-
-
-/**
- * 选择排序算法 Selection Sort v0.1.0
- *
- * @author coder-xiaomo
- * @date 2022-05-16
- */
-class SelectionSort extends Sort {
-
- info() {
- return {
- name: "选择排序算法",
- enName: "Selection Sort",
- available: true
- }
- }
-
- /*
- 重复(元素个数-1)次
- 把第一个没有排序过的元素设置为最小值
- 遍历每个没有排序过的元素
- 如果元素 < 现在的最小值
- 将此元素设置成为新的最小值
- 将最小值和第一个没有排序过的位置交换
- */
- sort(array) {
- let minIndex
- for (let i = 0; i < array.length; i++) {
- minIndex = i
- for (let j = i + 1; j < array.length; j++) {
- if (array[minIndex] > array[j]) {
- this.swap(array, minIndex, j)
- }
- }
- }
- return array
- }
-
- sortWithAnimation(customAttr, array) {
- let minIndex
- for (let i = 0; i < array.length; i++) {
- // console.log(array)
- minIndex = i
- for (let j = i + 1; j < array.length; j++) {
- animation.compareLinkedListItems(customAttr.id, minIndex, j)
- if (array[minIndex] > array[j]) {
- this.swap(array, minIndex, j)
- this.swapAnimation(customAttr.id, minIndex, j)
- }
- }
- }
- return array
- }
-}
-
-
-/**
- * 插入排序算法 Insertion Sort v0.1.0
- *
- * @author coder-xiaomo
- * @date 2022-05-18
- */
-class InsertionSort extends Sort {
-
- info() {
- return {
- name: "插入排序算法",
- enName: "Insertion Sort",
- available: true
- }
- }
-
- /*
- 将第一个元素标记为已排序
- 对于每一个未排序的元素 X
- “提取” 元素 X
- i = 最后排序过元素的索引 到 0 的遍历
- 如果当前元素 j > X
- 将排序过的元素向右移一格
- 跳出循环并在此插入 X
- */
- sort(array) {
- if (array.length == 0)
- return 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
- 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
- }
-}
-
-
-/**
- * 归并排序算法 Merge Sort v0.1.0
- *
- * @author coder-xiaomo
- * @date 2022-05-19
- */
-class MergeSort extends Sort {
-
- info() {
- return {
- name: "归并排序算法",
- enName: "Merge Sort",
- }
- }
-
- /*
- 将每个元素拆分成大小为1的分区
- 递归地合并相邻的分区
- 遍历 i = 左侧首项位置 到 右侧末项位置
- 如果左侧首项的值 <= 右侧首项的值
- 拷贝左侧首项的值
- 否则: 拷贝右侧首项的值; 增加逆序数
- 将元素拷贝进原来的数组中
- */
- sort(array) {
- if (array.length == 0)
- return array
- // todo
- console.log("尚未实现")
- return array
- }
-
- sortWithAnimation(customAttr, array) {
- if (array.length == 0)
- return array
- // todo
- console.log("尚未实现")
- return array
- }
-}
-
-
-/**
- * 随机快速排序算法 Random Quick Sort v0.1.0
- *
- * @author coder-xiaomo
- * @date 2022-05-19
- */
-class RandomQuickSort extends Sort {
-
- info() {
- return {
- name: "随机快速排序算法",
- enName: "Random Quick Sort",
- }
- }
-
- /*
- 每个(未排序)的部分
- 随机选取 pivot,和第一个元素交换
- 存储索引 = pivot索引 +1
- 从 i=pivot指数 +1 到 最右索引 的遍历
- 如果 a[i] < a[pivot]
- 交换 (i, 存储索引); 存储索引++;
- 交换(pivot, 存储索引 - 1)
- */
- sort(array) {
- if (array.length == 0)
- return array
- // todo
- console.log("尚未实现")
- return array
- }
-
- sortWithAnimation(customAttr, array) {
- if (array.length == 0)
- return array
- // todo
- console.log("尚未实现")
- return array
- }
-}
-
-
-/**
- * 计数排序算法 Counting Sort v0.1.0
- *
- * @author coder-xiaomo
- * @date 2022-05-19
- */
-class CountingSort extends Sort {
-
- info() {
- return {
- name: "计数排序算法",
- enName: "Counting Sort",
- }
- }
-
- /*
- 创建关键值(计数)数组
- 遍历数列中的每个元素
- 相应的计数器增加 1
- 每轮计数,都从最小的值开始
- 当计数为非零数时
- 重新将元素存储于列表
- 将计数减1
- */
- sort(array) {
- if (array.length == 0)
- return array
- // todo
- console.log("尚未实现")
- return array
- }
-
- sortWithAnimation(customAttr, array) {
- if (array.length == 0)
- return array
- // todo
- console.log("尚未实现")
- return array
- }
-}
-
-
-/**
- * 基数排序算法 Radix Sort v0.1.0
- *
- * @author coder-xiaomo
- * @date 2022-05-19
- */
-class RadixSort extends Sort {
-
- info() {
- return {
- name: "基数排序算法",
- enName: "Radix Sort",
- }
- }
-
- /*
- 分别给每个数位(0到9)创造1个桶(数列),共计10个
- 遍历每个数位
- 遍历数列中的每个元素
- 将元素移至相应的桶中
- 在每个桶中,从最小的数位开始
- 当桶不是空的
- 将元素恢复至数列中
- */
- sort(array) {
- if (array.length == 0)
- return array
- // todo
- console.log("尚未实现")
- return array
- }
-
- sortWithAnimation(customAttr, array) {
- if (array.length == 0)
- return array
- // todo
- console.log("尚未实现")
- return array
- }
-}
+/**
+ * 排序算法父类 Sort v0.1.0
+ *
+ * @author coder-xiaomo
+ * @date 2022-05-16
+ */
+
+function getSortClassList() {
+ return [
+ QuickSort,
+ BubbleSort,
+ SelectionSort,
+ InsertionSort,
+ MergeSort,
+ RandomQuickSort,
+ CountingSort,
+ RadixSort,
+ ]
+}
+
+class Sort {
+ static animation = null
+ constructor(animation) {
+ this.animation = animation
+ console.log(`初始化 ${this.info()['name']}`)
+ }
+
+ info() {
+ return {
+ name: "未命名算法",
+ available: false
+ }
+ }
+
+ sort(array) {
+ console.log("this method was not implement.")
+ return array
+ }
+
+ doSortWithAnimation(elementId) {
+ let customAttr = document.getElementById(elementId).customAttr
+ let array = JSON.parse(JSON.stringify(customAttr.nodes)) // 深拷贝一个数组
+ console.log(customAttr, array)
+ this.sortWithAnimation(customAttr, array)
+ }
+
+ sortWithAnimation(array) {
+ console.log("this method was not implement.")
+ return array
+ }
+
+ /**
+ * 交换数组中的两个元素
+ * @param {*} array 数组
+ * @param {*} index1 元素1索引
+ * @param {*} index2 元素2索引
+ */
+ swap(array, index1, index2) {
+ if (index1 < 0 || index1 >= array.length)
+ throw new Error("index1索引超限")
+ if (index2 < 0 || index2 >= array.length)
+ throw new Error("index2索引超限")
+ if (index1 == index2)
+ return
+
+ let tmp = array[index1]
+ array[index1] = array[index2]
+ array[index2] = tmp
+
+ // only for test
+ // console.log(Object.keys(array))
+ // console.log(array, index1, index2)
+ }
+ swapAnimation(id, index1, index2) {
+ if (index1 == index2)
+ return
+ animation.swapLinkedListItems(id, [index1, index2])
+ }
+}
+
+
+/**
+ * 快速排序算法 Qucik Sort v0.1.0
+ *
+ * @author coder-xiaomo
+ * @date 2022-05-16
+ */
+class QuickSort extends Sort {
+ /**
+ * step
+ *
+ * 1. 首先设定一个分界值,通过该分界值将数组分成左右两部分
+ * 2. 将大于或等于分界值的数据集中到数组右边,小于的集中到左边
+ * 3. 左右两侧的数组分别重复步骤 2.
+ * 4. 完成排序
+ */
+
+ info() {
+ return {
+ name: "快速排序算法",
+ enName: "Quick Sort",
+ available: true
+ }
+ }
+
+ /*
+ 每个(未排序)的部分
+ 将第一个元素设为 pivot
+ 存储索引 = pivot索引 +1
+ 从 i=pivot指数 +1 到 最右索引 的遍历
+ 如果 a[i] < a[pivot]
+ 交换 (i, 存储索引); 存储索引++;
+ 交换(pivot, 存储索引 - 1)
+ */
+ sort(array, left, right) {
+ if (typeof (left) === "undefined") left = 0
+ if (typeof (right) === "undefined") right = array.length - 1
+
+ if (right <= left)
+ return array // 递归出口
+
+ const pivot = left // 第一个元素的索引
+ let p = left + 1
+ for (let i = left + 1; i <= right; i++) {
+ if (array[i] < array[pivot]) {
+ this.swap(array, i, p)
+ p++
+ }
+ }
+ this.swap(array, pivot, p - 1)
+
+ // 左、右分别排序(索引超限在 sort 内部进行处理,此处无需判断)
+ this.sort(array, pivot, p - 2)
+ this.sort(array, p, right)
+ return array
+ }
+
+ sortWithAnimation(customAttr, array, left, right) {
+ if (typeof (left) === "undefined") left = 0
+ if (typeof (right) === "undefined") right = array.length - 1
+
+ if (right <= left)
+ return array // 递归出口
+
+ const pivot = left // 第一个元素的索引
+ let p = left + 1
+ for (let i = left + 1; i <= right; i++) {
+ animation.compareLinkedListItems(customAttr.id, i, pivot)
+ if (array[i] < array[pivot]) {
+ this.swap(array, i, p)
+ this.swapAnimation(customAttr.id, i, p)
+ p++
+ }
+ }
+ this.swap(array, pivot, p - 1)
+ this.swapAnimation(customAttr.id, pivot, p - 1)
+
+ // 左、右分别排序(索引超限在 sort 内部进行处理,此处无需判断)
+ this.sortWithAnimation(customAttr, array, pivot, p - 2)
+ this.sortWithAnimation(customAttr, array, p, right)
+ return array
+ }
+}
+
+
+/**
+ * 冒泡排序算法 Bubble Sort v0.1.0
+ *
+ * @author coder-xiaomo
+ * @date 2022-05-16
+ */
+class BubbleSort extends Sort {
+
+ info() {
+ return {
+ name: "冒泡排序算法",
+ enName: "Bubble Sort",
+ available: true
+ }
+ }
+
+ /*
+ 做
+ swapped = false
+ 从 i = 1 到 最后一个没有排序过元素的索引-1
+ 如果 左边元素 > 右边元素
+ 交换(左边元素,右边元素)
+ swapped = true; ++swapCounter(交换计数器)
+ while swapped
+ */
+ sort(array) {
+ let sortTime = 0
+ let swapped
+ do {
+ swapped = false
+ for (let i = 1; i < array.length - sortTime; i++) {
+ if (array[i - 1] > array[i]) {
+ this.swap(array, i - 1, i)
+ swapped = true
+ }
+ }
+ sortTime++
+ } while (swapped)
+
+ return array
+ }
+
+ sortWithAnimation(customAttr, array) {
+ let sortTime = 0
+ let swapped
+ do {
+ swapped = false
+ for (let i = 1; i < array.length - sortTime; i++) {
+ animation.compareLinkedListItems(customAttr.id, i - 1, i)
+ if (array[i - 1] > array[i]) {
+ this.swap(array, i - 1, i)
+ this.swapAnimation(customAttr.id, i - 1, i)
+ swapped = true
+ }
+ }
+ sortTime++
+ } while (swapped)
+
+ return array
+ }
+}
+
+
+/**
+ * 选择排序算法 Selection Sort v0.1.0
+ *
+ * @author coder-xiaomo
+ * @date 2022-05-16
+ */
+class SelectionSort extends Sort {
+
+ info() {
+ return {
+ name: "选择排序算法",
+ enName: "Selection Sort",
+ available: true
+ }
+ }
+
+ /*
+ 重复(元素个数-1)次
+ 把第一个没有排序过的元素设置为最小值
+ 遍历每个没有排序过的元素
+ 如果元素 < 现在的最小值
+ 将此元素设置成为新的最小值
+ 将最小值和第一个没有排序过的位置交换
+ */
+ sort(array) {
+ let minIndex
+ for (let i = 0; i < array.length; i++) {
+ minIndex = i
+ for (let j = i + 1; j < array.length; j++) {
+ if (array[minIndex] > array[j]) {
+ this.swap(array, minIndex, j)
+ }
+ }
+ }
+ return array
+ }
+
+ sortWithAnimation(customAttr, array) {
+ let minIndex
+ for (let i = 0; i < array.length; i++) {
+ // console.log(array)
+ minIndex = i
+ for (let j = i + 1; j < array.length; j++) {
+ animation.compareLinkedListItems(customAttr.id, minIndex, j)
+ if (array[minIndex] > array[j]) {
+ this.swap(array, minIndex, j)
+ this.swapAnimation(customAttr.id, minIndex, j)
+ }
+ }
+ }
+ return array
+ }
+}
+
+
+/**
+ * 插入排序算法 Insertion Sort v0.1.0
+ *
+ * @author coder-xiaomo
+ * @date 2022-05-18
+ */
+class InsertionSort extends Sort {
+
+ info() {
+ return {
+ name: "插入排序算法",
+ enName: "Insertion Sort",
+ available: true
+ }
+ }
+
+ /*
+ 将第一个元素标记为已排序
+ 对于每一个未排序的元素 X
+ “提取” 元素 X
+ i = 最后排序过元素的索引 到 0 的遍历
+ 如果当前元素 j > X
+ 将排序过的元素向右移一格
+ 跳出循环并在此插入 X
+ */
+ sort(array) {
+ if (array.length == 0)
+ return 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
+ 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
+ }
+}
+
+
+/**
+ * 归并排序算法 Merge Sort v0.1.0
+ *
+ * @author coder-xiaomo
+ * @date 2022-05-19
+ */
+class MergeSort extends Sort {
+
+ info() {
+ return {
+ name: "归并排序算法",
+ enName: "Merge Sort",
+ available: true
+ }
+ }
+
+ /*
+ 将每个元素拆分成大小为1的分区
+ 递归地合并相邻的分区
+ 遍历 i = 左侧首项位置 到 右侧末项位置
+ 如果左侧首项的值 <= 右侧首项的值
+ 拷贝左侧首项的值
+ 否则: 拷贝右侧首项的值; 增加逆序数
+ 将元素拷贝进原来的数组中
+ */
+ sort(array) {
+ if (array.length <= 1)
+ return array
+ let middle = Math.floor(array.length / 2)
+ let left = this.sort(array.slice(0, middle))
+ let right = this.sort(array.slice(middle))
+ let result = []
+ let i = 0, j = 0
+ while (i < left.length && j < right.length) {
+ if (left[i] <= right[j]) {
+ result.push(left[i])
+ i++
+ } else {
+ result.push(right[j])
+ j++
+ // this.reverseCount++
+ }
+ }
+ while (i < left.length) {
+ result.push(left[i])
+ i++
+ }
+ while (j < right.length) {
+ result.push(right[j])
+ j++
+ }
+ array = result
+ return array
+ }
+
+ sortWithAnimation(customAttr, array, arrayFirstElementIndex = 0) {
+ if (array.length <= 1) {
+ return array
+ }
+ console.log("array", array);
+
+ let middle = Math.floor(array.length / 2)
+ let left = this.sortWithAnimation(customAttr, array.slice(0, middle), arrayFirstElementIndex)
+ let right = this.sortWithAnimation(customAttr, array.slice(middle), arrayFirstElementIndex + middle)
+ let result = []
+ let i = 0, j = 0
+ while (i < left.length && j < right.length) {
+ if (left[i] <= right[j]) {
+ result.push(left[i])
+ animation.popupLinkedListItemToNewPosition(customAttr.id, arrayFirstElementIndex + i)
+ i++
+ } else {
+ result.push(right[j])
+ animation.popupLinkedListItemToNewPosition(customAttr.id, arrayFirstElementIndex + j)
+ j++
+ // this.reverseCount++
+ }
+ }
+ while (i < left.length) {
+ result.push(left[i])
+ animation.popupLinkedListItemToNewPosition(customAttr.id, arrayFirstElementIndex + i)
+ i++
+ }
+ while (j < right.length) {
+ result.push(right[j])
+ animation.popupLinkedListItemToNewPosition(customAttr.id, arrayFirstElementIndex + j)
+ j++
+ }
+ return result
+ }
+}
+
+
+/**
+ * 随机快速排序算法 Random Quick Sort v0.1.0
+ *
+ * @author coder-xiaomo
+ * @date 2022-05-19
+ */
+class RandomQuickSort extends Sort {
+
+ info() {
+ return {
+ name: "随机快速排序算法",
+ enName: "Random Quick Sort",
+ }
+ }
+
+ /*
+ 每个(未排序)的部分
+ 随机选取 pivot,和第一个元素交换
+ 存储索引 = pivot索引 +1
+ 从 i=pivot指数 +1 到 最右索引 的遍历
+ 如果 a[i] < a[pivot]
+ 交换 (i, 存储索引); 存储索引++;
+ 交换(pivot, 存储索引 - 1)
+ */
+ sort(array) {
+ if (array.length == 0)
+ return array
+ // todo
+ console.log("尚未实现")
+ return array
+ }
+
+ sortWithAnimation(customAttr, array) {
+ if (array.length == 0)
+ return array
+ // todo
+ console.log("尚未实现")
+ return array
+ }
+}
+
+
+/**
+ * 计数排序算法 Counting Sort v0.1.0
+ *
+ * @author coder-xiaomo
+ * @date 2022-05-19
+ */
+class CountingSort extends Sort {
+
+ info() {
+ return {
+ name: "计数排序算法",
+ enName: "Counting Sort",
+ }
+ }
+
+ /*
+ 创建关键值(计数)数组
+ 遍历数列中的每个元素
+ 相应的计数器增加 1
+ 每轮计数,都从最小的值开始
+ 当计数为非零数时
+ 重新将元素存储于列表
+ 将计数减1
+ */
+ sort(array) {
+ if (array.length == 0)
+ return array
+ // todo
+ console.log("尚未实现")
+ return array
+ }
+
+ sortWithAnimation(customAttr, array) {
+ if (array.length == 0)
+ return array
+ // todo
+ console.log("尚未实现")
+ return array
+ }
+}
+
+
+/**
+ * 基数排序算法 Radix Sort v0.1.0
+ *
+ * @author coder-xiaomo
+ * @date 2022-05-19
+ */
+class RadixSort extends Sort {
+
+ info() {
+ return {
+ name: "基数排序算法",
+ enName: "Radix Sort",
+ }
+ }
+
+ /*
+ 分别给每个数位(0到9)创造1个桶(数列),共计10个
+ 遍历每个数位
+ 遍历数列中的每个元素
+ 将元素移至相应的桶中
+ 在每个桶中,从最小的数位开始
+ 当桶不是空的
+ 将元素恢复至数列中
+ */
+ sort(array) {
+ if (array.length == 0)
+ return array
+ // todo
+ console.log("尚未实现")
+ return array
+ }
+
+ sortWithAnimation(customAttr, array) {
+ if (array.length == 0)
+ return array
+ // todo
+ console.log("尚未实现")
+ return array
+ }
+}
diff --git a/src/assets/js/algorithm/test.js b/src/assets/js/algorithm/test.js
index fff7d0e..96f2fe4 100644
--- a/src/assets/js/algorithm/test.js
+++ b/src/assets/js/algorithm/test.js
@@ -1,72 +1,73 @@
-
-/**
- * 排序算法测试
- */
-
-/**
- * 创建一个随机数数组
- * @returns
- */
-function getRandomData(count = 20) {
- var randomData = []
- for (let i = 0; i < count; i++) // 生成随机数
- randomData.push(Math.ceil(Math.random() * 100 - 50))
- return randomData
-}
-var data = [
- [],
- [-1],
- [1, 2],
- [1, 2, 3, 4, 5, 6, 7, 8],
- [8, 7, 6, 5, 4, 3, 2, 1],
- [1, 1, 1, 1, 1, 1, 1],
- [5, 8, 7, 4, 3, 1, 6, 2, 6, 5],
- [47, 11, 50, 13, 16, 49, 8, 9, 38, 27, 20],
- // getRandomData(6),
-]
-var check = [
- [],
- [-1],
- [1, 2],
- [1, 2, 3, 4, 5, 6, 7, 8],
- [1, 2, 3, 4, 5, 6, 7, 8],
- [1, 1, 1, 1, 1, 1, 1],
- [1, 2, 3, 4, 5, 5, 6, 6, 7, 8],
- [8, 9, 11, 13, 16, 20, 27, 38, 47, 49, 50],
- // null
-]
-
-var sortAlgorithm = {
- quicksort: new QuickSort(animation),
- bubblesort: new BubbleSort(animation),
- selectionSort: new SelectionSort(animation),
- insertionSort: new InsertionSort(animation),
-}
-
-// 遍历每一种算法
-Object.values(sortAlgorithm).forEach(sortAlgo => {
- // 输出调试信息
- console.log("算法信息", sortAlgo.info())
- data.forEach(element => {
- // 将数组元素进行深拷贝
- var input = JSON.parse(JSON.stringify(element))
- // 进行排序
- var result = sortAlgo.sort(input)
- console.log("before", element, "after", result)
- // 与结果进行对比,判断是否正确
- if (data.indexOf(element) > -1) {
- var rightSortResult = check[data.indexOf(element)];
- if (rightSortResult) {
- if (JSON.stringify(rightSortResult) !== JSON.stringify(result)) {
- console.warn("👆结果不匹配!正确结果为", rightSortResult)
- } else {
- console.info("👆正确")
- }
- } else {
- console.log("👆缺少正确答案,跳过")
- }
- }
- });
- // 输出一个空行,便于观察
- console.log("-----------------------------------------------")
-});
+
+/**
+ * 排序算法测试
+ */
+
+/**
+ * 创建一个随机数数组
+ * @returns
+ */
+function getRandomData(count = 20) {
+ var randomData = []
+ for (let i = 0; i < count; i++) // 生成随机数
+ randomData.push(Math.ceil(Math.random() * 100 - 50))
+ return randomData
+}
+var data = [
+ [],
+ [-1],
+ [1, 2],
+ [1, 2, 3, 4, 5, 6, 7, 8],
+ [8, 7, 6, 5, 4, 3, 2, 1],
+ [1, 1, 1, 1, 1, 1, 1],
+ [5, 8, 7, 4, 3, 1, 6, 2, 6, 5],
+ [47, 11, 50, 13, 16, 49, 8, 9, 38, 27, 20],
+ // getRandomData(6),
+]
+var check = [
+ [],
+ [-1],
+ [1, 2],
+ [1, 2, 3, 4, 5, 6, 7, 8],
+ [1, 2, 3, 4, 5, 6, 7, 8],
+ [1, 1, 1, 1, 1, 1, 1],
+ [1, 2, 3, 4, 5, 5, 6, 6, 7, 8],
+ [8, 9, 11, 13, 16, 20, 27, 38, 47, 49, 50],
+ // null
+]
+
+var sortAlgorithm = {
+ quicksort: new QuickSort(animation),
+ bubblesort: new BubbleSort(animation),
+ selectionSort: new SelectionSort(animation),
+ insertionSort: new InsertionSort(animation),
+ mergeSort: new MergeSort(animation),
+}
+
+// 遍历每一种算法
+Object.values(sortAlgorithm).forEach(sortAlgo => {
+ // 输出调试信息
+ console.log("算法信息", sortAlgo.info())
+ data.forEach(element => {
+ // 将数组元素进行深拷贝
+ var input = JSON.parse(JSON.stringify(element))
+ // 进行排序
+ var result = sortAlgo.sort(input)
+ console.log("before", element, "after", result)
+ // 与结果进行对比,判断是否正确
+ if (data.indexOf(element) > -1) {
+ var rightSortResult = check[data.indexOf(element)];
+ if (rightSortResult) {
+ if (JSON.stringify(rightSortResult) !== JSON.stringify(result)) {
+ console.warn("👆结果不匹配!正确结果为", rightSortResult)
+ } else {
+ console.info("👆正确")
+ }
+ } else {
+ console.log("👆缺少正确答案,跳过")
+ }
+ }
+ });
+ // 输出一个空行,便于观察
+ console.log("-----------------------------------------------")
+});
diff --git a/src/assets/js/class.js b/src/assets/js/class.js
index cbe7d51..268f70d 100644
--- a/src/assets/js/class.js
+++ b/src/assets/js/class.js
@@ -1,647 +1,695 @@
-/**
- * WorkSpace class v0.1.0
- *
- * @author coder-xiaomo
- * @date 2022-05-15
- *
- * Released under the MIT license
- */
-class WorkSpace {
- static settings = null;
- static primaryCanvas = null;
-
- constructor(settings) {
- this.settings = settings
- settings.workSpace = this
-
- // 清除原有内容
- settings.container
- .style("width", settings.width)
- .style("height", settings.height)
- // .attr("width", settings.width)
- // .attr("height", settings.height)
- .html("")
-
- // 创建工作区SVG
- this.primaryCanvas = settings.container.append("svg")
- // 添加id
- .attr("id", "primaryCanvas")
- // 设置 SVG 宽高
- .attr("width", "100%")
- .attr("height", "100%")
- // 背景色
- .style("background-color", settings.colorMap["background"])
- }
-}
-
-class ViBase {
- static workSpace = null;
- constructor(workSpace) {
- this.workSpace = workSpace
- }
-}
-class ArrayVi extends ViBase {
- // [47, 11, 50, 13, 16, 49, 8, 9, 38, 27, 20]
- // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
- static listData
-
- // 网页加载完毕初始化事件
- initialize({ elementId }) {
- let controlDiv = document.getElementById("control-div")
- controlDiv.style.textAlign = "center"
-
- var sortClassList = getSortClassList();
- console.log(sortClassList);
- var DOMFragment = document.createDocumentFragment()
-
- var selector = document.createElement("select")
- for (let i = 0; i < sortClassList.length; i++) {
- const sortClass = new sortClassList[i](animation)
- const sortClassInfo = sortClass.info()
-
- // 跳过未完成的算法
- if (!sortClassInfo['available'])
- continue
-
- let option = document.createElement("option")
- option.value = sortClassInfo['name']
- option.innerText = sortClassInfo['name']
- selector.appendChild(option)
- }
- DOMFragment.appendChild(selector)
-
- let ctrlBtn = document.createElement("button")
- ctrlBtn.innerHTML = "开始排序"
- let that = this
- ctrlBtn.onclick = function () {
- // 点击排序算法按钮
- // if (!that.updateListDataArray(elementId, { doNotAlert: false }))
- // return
- if (!that.listData || that.listData.length == 0) {
- alert("数组为空")
- return
- }
-
- // 隐藏一些东西,显示一些东西
- controlDiv.style.display = 'none'
- d3.select("#console-div")
- .style("display", "")
- d3.select("#console-current-algorithm")
- .style("text-align", "center")
- .html(selector.value/*sortClassInfo['name']*/)
-
- // 找到对应的算法,然后开始排序
- for (let i = 0; i < sortClassList.length; i++) {
- const sortClass = new sortClassList[i](animation)
- const sortClassInfo = sortClass.info()
-
- if (sortClassInfo['name'] === selector.value) {
- sortClass.doSortWithAnimation(elementId)
- break
- }
- }
- }
- DOMFragment.appendChild(ctrlBtn)
-
- // 页面最后更新时间
- var lastModifiedTime = (new Date(document.lastModified).getTime() / 1000).toFixed(0)
- let lastModifiedDiv = document.createElement("div")
- lastModifiedDiv.style.fontSize = "x-small"
- lastModifiedDiv.style.opacity = ".5"
- lastModifiedDiv.innerHTML = "页面版本戳: " + lastModifiedTime
- DOMFragment.appendChild(lastModifiedDiv)
-
- controlDiv.appendChild(DOMFragment)
-
- // 生成一个随机数组
- this.randomListDataArray(elementId)
-
- // 显示 siderbar
- d3.select("#sidebar").style("display", "")
- }
-
- // 将数组显示到输入框中
- updateListDataInput() {
- document.getElementById("array-input").value = this.listData.join(",")
- }
-
- // Array 内容改变时
- updateListDataArray(elementId, { doNotAlert = false }) {
- var val = document.getElementById("array-input").value
- try {
- var preList = val.replaceAll(",", ",").split(",")
- this.listData = []
- preList.forEach(element => {
- if (element.trim() === "" || isNaN(element))
- return
- this.listData.push(Number(element))
- });
- arrayVi.initArray(elementId, this.listData)
- } catch (err) {
- console.log(err)
- if (!doNotAlert)
- alert("输入不正确,请检查!")
- return false
- }
- return true
- }
-
- // 随机 Array
- randomListDataArray(elementId) {
- function getRandom(length) {
- return Math.floor(Math.random() * length); // 可均衡获取 0 到 length-1 的随机整数。
- }
- // 获取一个 6 - 12 以内的随机数
- var len = 6 + getRandom(13 - 6)
-
- this.listData = []
- for (let i = 0; i < len; i++) {
- this.listData.push(getRandom(51))
- }
- this.updateListDataInput()
- this.updateListDataArray(elementId, { doNotAlert: false })
- }
-
- // 绘制数组
- initArray(elementId, listData) {
- console.log("initArray")
- let fragment = shape.getLinkedListFragment(elementId, listData, {
- x: 100,
- y: 100,
- width: "100px",
- height: "100px",
- })
-
- // console.log(fragment)
- workSpace.primaryCanvas.html("")
-
- // 添加水印 居中
- var watermarkWidth = settings.outerSize.height * 0.65
- shape.addWatermark(elementId, {
- imageSrc: "./assets/image/logo-small.svg",
- })
- .attr('id', 'watermark-c-c')
- .attr('x', settings.outerSize.width / 2)
- .attr('y', settings.outerSize.height / 2)
- .style('width', watermarkWidth + 'px')
- .style('height', watermarkWidth + 'px')
- .style('transform', `translate(-${watermarkWidth / 2}px, -${watermarkWidth / 2}px)`)
- .style('opacity', '0.015')
- .style('transition', '0.2s')
-
- // 添加水印 右下角
- var watermarkWidth = 60
- shape.addWatermark(elementId, {
- imageSrc: "./assets/image/logo-small.svg",
- })
- .attr('id', 'watermark-r-b')
- .attr('x', settings.outerSize.width)
- .attr('y', settings.outerSize.height)
- .style('width', watermarkWidth + 'px')
- .style('height', watermarkWidth + 'px')
- .style('transform', 'translate(-80px, -80px)')
-
- workSpace.primaryCanvas.node().appendChild(fragment)
- document.getElementById(elementId).customAttr = fragment.customAttr
- }
-}
-
-/**
- * Shape class v0.1.0
- *
- * @author coder-xiaomo
- * @date 2022-05-15
- *
- * Released under the MIT license
- */
-class Shape {
- static workSpace = null;
- constructor(workSpace) {
- this.workSpace = workSpace
- }
-
- addShape(shape, id) {
- var settings = this.workSpace.settings
- return workSpace.primaryCanvas.append(shape)
- .style("transform", `translate(${settings.margin.left}px, ${settings.margin.top}px)`)
- .attr("id", id)
- }
- addShape_NoTransform(shape, id) {
- return workSpace.primaryCanvas.append(shape)
- .attr("id", id)
- }
-
- // 添加矩形
- rectangle(id, { x, y, width, height, fillColor = "white", strokeColor = "black" }) {
- return this.addShape("rect", id)
- .attr("x", x)
- .attr("y", y)
- .attr("width", width)
- .attr("height", height)
- .style("fill", fillColor)
- .style("stroke", strokeColor)
- }
-
- // 添加圆形
- circle(id, { x, y, radius, fillColor = "white", strokeColor = "black" }) {
- return this.addShape("circle", id)
- .attr("cx", x)
- .attr("cy", y)
- .attr("r", radius)
- .style("fill", fillColor)
- .style("stroke", strokeColor)
- }
-
- // 添加文本
- text(id, { x, y, text, fillColor }) {
- return this.addShape("text", id)
- .attr("x", x)
- .attr("y", y)
- .text(text)
- .style("fill", fillColor)
- }
-
- // 添加线
- line(id, { x1, y1, x2, y2, strokeColor }) {
- return this.addShape("line", id)
- .attr("x1", x1)
- .attr("y1", y1)
- .attr("x2", x2)
- .attr("y2", y2)
- .style("stroke", strokeColor)
- }
-
- // 添加路径
- path(id, d, { fillColor = "white", strokeColor = "black" }) {
- return this.addShape("path", id)
- .attr("d", d)
- .style("fill", fillColor)
- .style("stroke", strokeColor)
- }
-
- // 添加坐标轴
- axis(id, { transform, axis }) {
- return this.addShape_NoTransform("g", id)
- .attr("transform", transform)
- .call(axis)
- }
-
- // 添加一个链表节点
- addNode(id, x, y, width, height, text) {
- var primaryCanvas = workSpace.primaryCanvas
- primaryCanvas.append("rect", id)
- .attr("x", x)
- .attr("y", y)
- .attr("width", width)
- .attr("height", height)
- .style("fill", workSpace.settings.colorMap["fill"])
- .style("stroke", workSpace.settings.colorMap["stroke"])
- primaryCanvas.append("text", id + "_text")
- .attr("x", x)
- .attr("y", y)
- // .attr("x", x + width / 2)
- // .attr("y", y + height / 2)
- .text(text)
- .style("fill", workSpace.settings.colorMap["text"])
- }
-
-
- // 添加一个图片水印
- addWatermark(id, { imageSrc }) {
- var primaryCanvas = workSpace.primaryCanvas
- return primaryCanvas.append("image", id)
- .attr("xlink:href", imageSrc)
- }
-
- // 绘制一个链表
- getLinkedListFragment(id, nodes) {
- var settings = this.workSpace.settings
-
- let displayMaxWidth = 1 * settings.innerSize.width
- let displayMaxHeight = 1 * settings.innerSize.height
- let areaWidth = 1 * nodes.length // 按照1个Unit来计算
- let areaHeight = 1 // 按照1个Unit来计算
-
- let oneUnit = 100
- // 可以假设高度相等比较宽度,这样好理解
- if (displayMaxWidth / displayMaxHeight > areaWidth / areaHeight) {
- // 展示区域左右有多余空间
- oneUnit = displayMaxHeight / areaHeight
- } else {
- // 展示区域上下有空间(或刚刚好)
- oneUnit = displayMaxWidth / areaWidth
- }
-
- // 定义最大值
- if (oneUnit > 120) oneUnit = 120
-
- let fragment = document.createDocumentFragment()
- fragment.customAttr = {
- id: id,
- nodes: nodes,
- type: "linkedList",
- oneUnit: oneUnit,
- gsapTimeline: gsap.timeline({
- onStart: function () {
- consoleClear()
- },
- onComplete: function () {
- consoleLog(`排序完成`)
- console.log("all done")
- // this.seek(0)
- }
- })
- }
- // console.log(fragment.customAttr)
-
- //