• O：极点，也就是原点
• ρ：极径
• θ：极径与X轴夹角
• x = ρ * cosθ，因为x / ρ = cosθ
• y = ρ * sinθ，因为y / ρ = sinθ

const arr = [
0, 1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34, 35, 36
]

• 元素对应的索引index * 10 -> 角度θ(为什么要乘10呢，因为要凑够360°嘛)
• 元素对应的值arr[index] -> 极径ρ

(0 -> θ = 00°，ρ = 0) (1 -> θ = 10°，ρ = 1) (2 -> θ = 20°，ρ = 2) (3 -> θ = 30°，ρ = 3)
(4 -> θ = 40°，ρ = 4) (5 -> θ = 50°，ρ = 5) (6 -> θ = 60°，ρ = 6) (7 -> θ = 70°，ρ = 7)
(8 -> θ = 80°，ρ = 8) (9 -> θ = 90°，ρ = 9) (10 -> θ = 100°，ρ = 10) (11 -> θ = 110°，ρ = 11)
(12 -> θ = 120°，ρ = 12) (13 -> θ = 130°，ρ = 13) (14 -> θ = 140°，ρ = 14) (15 -> θ = 150°，ρ = 15)
(16 -> θ = 160°，ρ = 16) (17 -> θ = 170°，ρ = 17) (18 -> θ = 180°，ρ = 18) (19 -> θ = 190°，ρ = 19)
(20 -> θ = 200°，ρ = 20) (21 -> θ = 210°，ρ = 21) (22 -> θ = 220°，ρ = 22) (23 -> θ = 230°，ρ = 23)
(24 -> θ = 240°，ρ = 24) (25 -> θ = 250°，ρ = 25) (26 -> θ = 260°，ρ = 26) (27 -> θ = 270°，ρ = 27)
(28 -> θ = 280°，ρ = 28) (29 -> θ = 290°，ρ = 29) (30 -> θ = 300°，ρ = 30) (31 -> θ = 310°，ρ = 31)
(32 -> θ = 320°，ρ = 32) (33 -> θ = 330°，ρ = 33) (34 -> θ = 340°，ρ = 34) (35 -> θ = 350°，ρ = 35)
(36 -> θ = 360°，ρ = 36)

const arr = [
25, 8, 32, 1, 19, 14, 0, 29, 17,
6, 7, 26, 3, 30, 31, 16, 28, 15,
24, 10, 21, 2, 9, 4, 35, 5, 36,
33, 11, 27, 34, 22, 13, 18, 23, 12, 20
]

• 元素对应的索引index * 10 -> 角度θ(为什么要乘10呢，因为要凑够360°嘛)
• 元素对应的值arr[index] -> 极径ρ

(25 -> θ = 00°，ρ = 25) (8 -> θ = 10°，ρ = 8) (32 -> θ = 20°，ρ = 32) (1 -> θ = 30°，ρ = 1)
(19 -> θ = 40°，ρ = 19) (14 -> θ = 50°，ρ = 14) (0 -> θ = 60°，ρ = 0) (29 -> θ = 70°，ρ = 29)
(17 -> θ = 80°，ρ = 17) (6 -> θ = 90°，ρ = 6) (7 -> θ = 100°，ρ = 7) (26 -> θ = 110°，ρ = 26)
(3 -> θ = 120°，ρ = 3) (30 -> θ = 130°，ρ = 30) (31 -> θ = 140°，ρ = 31) (16 -> θ = 150°，ρ = 16)
(28 -> θ = 160°，ρ = 28) (15 -> θ = 170°，ρ = 15) (24 -> θ = 180°，ρ = 24) (10 -> θ = 190°，ρ = 10)
(21 -> θ = 200°，ρ = 21) (2 -> θ = 210°，ρ = 2) (9 -> θ = 220°，ρ = 9) (4 -> θ = 230°，ρ = 4)
(35 -> θ = 240°，ρ = 35) (5 -> θ = 250°，ρ = 5) (36 -> θ = 260°，ρ = 36) (33 -> θ = 270°，ρ = 33)
(11 -> θ = 280°，ρ = 11) (27 -> θ = 290°，ρ = 27) (34 -> θ = 300°，ρ = 34) (22 -> θ = 310°，ρ = 22)
(13 -> θ = 320°，ρ = 13) (18 -> θ = 330°，ρ = 18) (23 -> θ = 340°，ρ = 23) (12 -> θ = 350°，ρ = 12)
(20 -> θ = 360°，ρ = 20)

• 1、先生成一个乱序数组
• 2、用canvas画布画出此乱序数组所有元素对应的极坐标对应的点
• 3、对乱序数组进行排序
• 4、排序过程中不断清空画布，并重画数组所有元素对应的极坐标对应的点
• 5、直到排序完成，终止画布操作

• 1、先生成一个乱序数组
• 2、用canvas画布画出此乱序数组所有元素对应的极坐标对应的点
• 3、对乱序数组进行排序
• 4、排序过程中不断清空画布，并重画数组所有元素对应的极坐标对应的点
• 5、直到排序完成，终止画布操作

let nums = []
for (let i = 0; i < 4; i++) {
// 生成一个 0 - 179的有序数组
const arr = [...Array(180).keys()] // Array.keys()可以学一下，很有用
const res = []
while (arr.length) {
// 打乱
const randomIndex = Math.random() * arr.length - 1
res.push(arr.splice(randomIndex, 1)[0])
}
nums = [...nums, ...res]
}

canvas画乱序数组

<canvas  width="1000" height="1000" style="background: #000;"></canvas>

const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
ctx.fillStyle = 'white' // 设置画画的颜色
ctx.translate(500, 500) // 移动中心点到(500, 500)

• x = ρ * cosθ，因为x / ρ = cosθ
• y = ρ * sinθ，因为y / ρ = sinθ

const CosandSin = []
for (let i = 0; i < 360; i++) {
const jiaodu = i / 180 * Math.PI
CosandSin.push({ cos: Math.cos(jiaodu), sin: Math.sin(jiaodu) })
}

// 单个长方形构造函数
function Rect(x, y, width, height) {
this.x = x // 坐标x
this.y = y // 坐标y
this.width = width // 长方形的宽
this.height = height // 长方形的高
}

// 单个长方形的渲染函数
Rect.prototype.draw = function () {
ctx.beginPath() // 开始画一个
ctx.fillRect(this.x, this.y, this.width, this.height) // 画一个
ctx.closePath() // 结束画一个
}

const CosandSin = []
for (let i = 0; i < 360; i++) {
const jiaodu = i / 180 * Math.PI
CosandSin.push({ cos: Math.cos(jiaodu), sin: Math.sin(jiaodu) })
}

function drawAll(arr) {
const rects = [] // 用来存储720个长方形
for (let i = 0; i < arr.length; i++) {
const num = arr[i]
const { cos, sin } = CosandSin[Math.floor(i / 2)] // 一个角画两个
const x = num * cos // x = ρ * cosθ
const y = num * sin // y = ρ * sinθ
rects.push(new Rect(x, y, 5, 3)) // 收集所有长方形
}
rects.forEach(rect => rect.draw()) // 遍历渲染
}
drawAll(nums) // 执行渲染函数

function drawAll(arr) {
return new Promise((resolve) => {
setTimeout(() => {
ctx.clearRect(-500, -500, 1000, 1000) // 清空画布
const rects = [] // 用来存储720个长方形
for (let i = 0; i < arr.length; i++) {
const num = arr[i]
const { cos, sin } = CosandSin[Math.floor(i / 2)] // 一个角画两个
const x = num * cos // x = ρ * cosθ
const y = num * sin // y = ρ * sinθ
rects.push(new Rect(x, y, 5, 3)) // 收集所有长方形
}
rects.forEach(rect => rect.draw()) // 遍历渲染
resolve('draw success')
}, 10)
})
}

async function bubbleSort(arr) {
var len = arr.length;
for (var i = 0; i < len; i++) {
for (var j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {        //相邻元素两两对比
var temp = arr[j + 1];        //元素交换
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
await drawAll(arr) // 一边排序一边重新画
}
return arr;
}

<button >开始排序</button>

document.getElementById('btn').onclick = function () {
bubbleSort(nums)
}

<canvas  width="1000" height="1000" style="background: #000;"></canvas>
<button >开始排序</button>

const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
ctx.fillStyle = 'white' // 设置画画的颜色
ctx.translate(500, 500) // 移动中心点到(500, 500)

let nums = []
for (let i = 0; i < 4; i++) {
// 生成一个 0 - 180的有序数组
const arr = [...Array(180).keys()]
const res = []
while (arr.length) {
// 打乱
const randomIndex = Math.random() * arr.length - 1
res.push(arr.splice(randomIndex, 1)[0])
}
nums = [...nums, ...res]
}

// 单个长方形构造函数
function Rect(x, y, width, height) {
this.x = x // 坐标x
this.y = y // 坐标y
this.width = width // 长方形的宽
this.height = height // 长方形的高
}

// 单个长方形的渲染函数
Rect.prototype.draw = function () {
ctx.beginPath() // 开始画一个
ctx.fillRect(this.x, this.y, this.width, this.height) // 画一个
ctx.closePath() // 结束画一个
}

const CosandSin = []
for (let i = 0; i < 360; i++) {
const jiaodu = i / 180 * Math.PI
CosandSin.push({ cos: Math.cos(jiaodu), sin: Math.sin(jiaodu) })
}

function drawAll(arr) {
return new Promise((resolve) => {
setTimeout(() => {
ctx.clearRect(-500, -500, 1000, 1000) // 清空画布
const rects = [] // 用来存储720个长方形
for (let i = 0; i < arr.length; i++) {
const num = arr[i]
const { cos, sin } = CosandSin[Math.floor(i / 2)] // 一个角画两个
const x = num * cos // x = ρ * cosθ
const y = num * sin // y = ρ * sinθ
rects.push(new Rect(x, y, 5, 3)) // 收集所有长方形
}
rects.forEach(rect => rect.draw()) // 遍历渲染
resolve('draw success')
}, 10)
})
}
drawAll(nums) // 执行渲染函数

async function bubbleSort(arr) {
var len = arr.length;
for (var i = 0; i < len; i++) {
for (var j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {        //相邻元素两两对比
var temp = arr[j + 1];        //元素交换
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
await drawAll(arr) // 一边排序一边重新画
}
return arr;
}

document.getElementById('btn').onclick = function () {
bubbleSort(nums) // 点击执行
}

• 我是算法渣渣
• 每种算法排序，动画都不一样
• drawAll放在不同地方也可能有不同效果

async function bubbleSort(arr) {
var len = arr.length;
for (var i = 0; i < len; i++) {
for (var j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {        //相邻元素两两对比
var temp = arr[j + 1];        //元素交换
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
await drawAll(arr) // 一边排序一边重新画
}
return arr;
}

document.getElementById('btn').onclick = function () {
bubbleSort(nums) // 点击执行
}

async function selectionSort(arr) {
var len = arr.length;
var minIndex, temp;
for (var i = 0; i < len - 1; i++) {
minIndex = i;
for (var j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) {     //寻找最小的数
minIndex = j;                 //将最小数的索引保存
}
}
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
await drawAll(arr)
}
return arr;
}
document.getElementById('btn').onclick = function () {
selectionSort(nums)
}

async function insertionSort(arr) {
if (Object.prototype.toString.call(arr).slice(8, -1) === 'Array') {
for (var i = 1; i < arr.length; i++) {
var key = arr[i];
var j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
await drawAll(arr)
}
return arr;
} else {
return 'arr is not an Array!';
}
}
document.getElementById('btn').onclick = function () {
insertionSort(nums)
}

async function heapSort(array) {
if (Object.prototype.toString.call(array).slice(8, -1) === 'Array') {
//建堆
var heapSize = array.length, temp;
for (var i = Math.floor(heapSize / 2) - 1; i >= 0; i--) {
heapify(array, i, heapSize);
await drawAll(array)
}

//堆排序
for (var j = heapSize - 1; j >= 1; j--) {
temp = array[0];
array[0] = array[j];
array[j] = temp;
heapify(array, 0, --heapSize);
await drawAll(array)
}
return array;
} else {
return 'array is not an Array!';
}
}
function heapify(arr, x, len) {
if (Object.prototype.toString.call(arr).slice(8, -1) === 'Array' && typeof x === 'number') {
var l = 2 * x + 1, r = 2 * x + 2, largest = x, temp;
if (l < len && arr[l] > arr[largest]) {
largest = l;
}
if (r < len && arr[r] > arr[largest]) {
largest = r;
}
if (largest != x) {
temp = arr[x];
arr[x] = arr[largest];
arr[largest] = temp;
heapify(arr, largest, len);
}
} else {
return 'arr is not an Array or x is not a number!';
}
}
document.getElementById('btn').onclick = function () {
heapSort(nums)
}

async function quickSort(array, left, right) {
drawAll(nums)
if (Object.prototype.toString.call(array).slice(8, -1) === 'Array' && typeof left === 'number' && typeof right === 'number') {
if (left < right) {
var x = array[right], i = left - 1, temp;
for (var j = left; j <= right; j++) {
if (array[j] <= x) {
i++;
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
await drawAll(nums)
await quickSort(array, left, i - 1);
await quickSort(array, i + 1, right);
await drawAll(nums)
}
return array;
} else {
return 'array is not an Array or left or right is not a number!';
}
}
document.getElementById('btn').onclick = function () {
quickSort(nums, 0, nums.length - 1)
}

async function radixSort(arr, maxDigit) {
var mod = 10;
var dev = 1;
var counter = [];
for (var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
for (var j = 0; j < arr.length; j++) {
var bucket = parseInt((arr[j] % mod) / dev);
if (counter[bucket] == null) {
counter[bucket] = [];
}
counter[bucket].push(arr[j]);
}
var pos = 0;
for (var j = 0; j < counter.length; j++) {
var value = null;
if (counter[j] != null) {
while ((value = counter[j].shift()) != null) {
arr[pos++] = value;
await drawAll(arr)
}
}
}
}
return arr;
}
document.getElementById('btn').onclick = function () {
}

async function shellSort(arr) {
var len = arr.length,
temp,
gap = 1;
while (gap < len / 5) {          //动态定义间隔序列
gap = gap * 5 + 1;
}
for (gap; gap > 0; gap = Math.floor(gap / 5)) {
for (var i = gap; i < len; i++) {
temp = arr[i];
for (var j = i - gap; j >= 0 && arr[j] > temp; j -= gap) {
arr[j + gap] = arr[j];
}
arr[j + gap] = temp;
await drawAll(arr)
}
}
return arr;
}
document.getElementById('btn').onclick = function () {
shellSort(nums)
}


• 排序算法参考：十大经典排序算法总结（JavaScript描述）