26浏览
查看: 26|回复: 5

[项目] 【花雕动手做】基于 Kitronik 可编程开发板之排序算法

[复制链接]
Kitronik ARCADE 是一款由英国教育科技公司 Kitronik 精心打造的可编程游戏机开发板,专为编程教学与创客实践而设计。该设备原生支持微软的 MakeCode Arcade 平台,用户可通过图形化或 JavaScript 编程方式,轻松创建、下载并运行复古风格的街机游戏。

它集成了彩色 LCD 显示屏、方向控制键、功能按键、蜂鸣器和震动马达等交互组件,提供完整的游戏输入输出体验。无论是初学者进行编程启蒙,还是创客群体开发交互式作品,Kitronik ARCADE 都能作为理想的硬件载体,助力创意实现。

凭借其开源友好、易于上手、兼容性强等特点,该开发板广泛应用于中小学编程课程、创客工作坊、游戏开发教学以及个人项目原型设计,深受教育者与技术爱好者的喜爱。

【花雕动手做】基于 Kitronik 可编程开发板之排序算法图1

【花雕动手做】基于 Kitronik 可编程开发板之排序算法图2

【花雕动手做】基于 Kitronik 可编程开发板之排序算法图3

驴友花雕  中级技神
 楼主|

发表于 昨天 07:05

【花雕动手做】基于 Kitronik 可编程开发板之排序算法

作为学习、练习与尝试,这里创建一个排序算法的小游戏。
打开网页版:https://arcade.makecode.com/,设置项目名称:排序算法

JavaScript 实验代码

  1. const pauseDuration = 10;
  2. interface SortingAlgorithm {
  3.     title: string;
  4.     algorithm: (values: number[]) => number[];
  5.     a?: number[];
  6.     place?: string;
  7. }
  8. let currCount = 26;
  9. let currentRun = 0;
  10. let ySegment: number;
  11. let currentPlace: number;
  12. let running: SortingAlgorithm[] = [];
  13. let notRunning: SortingAlgorithm[] = [];
  14. addExample("selection sort", sorts.selectionSort);
  15. addExample("insertion sort", sorts.insertionSort);
  16. addExample("bubble sort", sorts.bubbleSort);
  17. addExample("shell sort", sorts.shellSort);
  18. addExample("heap sort", sorts.heapSort);
  19. addExample("quick sort", sorts.quickSort);
  20. addExample("merge sort", sorts.mergeSort);
  21. // Start off with two random algorithms running
  22. for (let i = 0; i < 2; i++) {
  23.     moveRandom(notRunning, running);
  24. }
  25. start();
  26. game.onPaint(() => {
  27.     running.forEach(function (value: SortingAlgorithm, index: number) {
  28.         drawCurrentState(value, currCount, ySegment, index * ySegment);
  29.     });
  30. });
  31. // start over with a new seed
  32. controller.A.onEvent(ControllerButtonEvent.Pressed, () => {
  33.     start();
  34. });
  35. // remove a sorting algorithm from the group of running sorts
  36. controller.left.onEvent(ControllerButtonEvent.Pressed, () => {
  37.     if (running.length > 1) {
  38.         moveRandom(running, notRunning)
  39.         start();
  40.     }
  41. });
  42. // display a new sorting algorithm if possible
  43. controller.right.onEvent(ControllerButtonEvent.Pressed, () => {
  44.     if (notRunning.length > 0) {
  45.         moveRandom(notRunning, running)
  46.         start();
  47.     }
  48. });
  49. // increase the number of elements to sort if possible
  50. controller.up.onEvent(ControllerButtonEvent.Pressed, function () {
  51.     if (currCount + 6 < screen.width / 2) {
  52.         currCount += 6;
  53.         start();
  54.     }
  55. });
  56. // decrease the number of elements to sort if possible
  57. controller.down.onEvent(ControllerButtonEvent.Pressed, function () {
  58.     if (currCount > 6) {
  59.         currCount -= 6;
  60.         start();
  61.     }
  62. })
  63. function moveRandom<T>(a: T[], b: T[]) {
  64.     if (a.length > 0) {
  65.         const i = randint(0, a.length - 1);
  66.         b.push(a.removeAt(i));
  67.     }
  68. }
  69. function addExample(title: string, sortAlgorithm: (values: number[]) => number[]) {
  70.     let output: SortingAlgorithm = {
  71.         title: title,
  72.         algorithm: sortAlgorithm
  73.     }
  74.     notRunning.push(output);
  75. }
  76. function start() {
  77.     const r = new Math.FastRandom();
  78.     ++currentRun;
  79.     currentPlace = 1;
  80.     ySegment = Math.floor(screen.height / running.length);
  81.     // clear old arrays to quickly cull other threads as much as possible;
  82.     // only merge sort will survive as it is not in place
  83.     running.forEach(v => {
  84.         while (v.a && v.a.length != 0)
  85.             v.a.pop();
  86.     });
  87.     // create a new starting array for each of the algorithms
  88.     running.forEach(v => v.a = fillWithDefault(r, currCount, ySegment - (image.font5.charHeight + 2)));
  89.     // run the comparison
  90.     running.forEach(v => control.runInParallel(() => {
  91.         const run = currentRun;
  92.         v.place = undefined;
  93.         v.algorithm(v.a);
  94.         if (run === currentRun) {
  95.             const place = currentPlace++;
  96.             if (place === 1)
  97.                 music.powerUp.play();
  98.             else if (place === running.length)
  99.                 music.wawawawaa.play();
  100.             // ordinal indicator is 'st', 'nd', 'rd', or 'th'
  101.             v.place = place + ordinalIndicator(place);
  102.         }
  103.     }));
  104. }
  105. function fillWithDefault(r: Math.FastRandom, count: number, maxHeight: number): number[] {
  106.     // reset seed so that output is consistent
  107.     r.reset();
  108.     let output: number[] = [];
  109.     for (let i = 0; i < count; ++i) {
  110.         output.push(r.randomRange(0, maxHeight));
  111.     }
  112.     return output;
  113. }
  114. function drawCurrentState(s: SortingAlgorithm, count: number, height: number, yOffset: number) {
  115.     const a = s.a
  116.     const title = s.title;
  117.     const lineWidth = Math.floor(screen.width / count) - 1;
  118.     const borderWidth = (screen.width - (count * (lineWidth + 1))) / 2;
  119.     for (let i = 0; i < a.length; ++i) {
  120.         if (a[i] > 0) {
  121.             const maxValue = ySegment - (image.font5.charHeight + 2);
  122.             // pick color between 0x1 and 0xE based on value
  123.             let c = Math.clamp(0x1, 0xE, Math.floor(a[i] * 14 / maxValue));
  124.             screen.fillRect(borderWidth + i * (lineWidth + 1), height + yOffset - a[i], lineWidth, a[i], c);
  125.         }
  126.     }
  127.     screen.print(title, borderWidth, yOffset + 1, 0x2, image.font5);
  128.     if (s.place)
  129.         screen.print(s.place, borderWidth, yOffset + 3 + image.font5.charHeight, 0x2, image.font5);
  130. }
  131. function ordinalIndicator(input: number) {
  132.     const lastDigit = input % 10;
  133.     if (lastDigit === 1)
  134.         return "st";
  135.     else if (lastDigit === 2)
  136.         return "nd";
  137.     else if (lastDigit === 3)
  138.         return "rd";
  139.     else
  140.         return "th";
  141. }
  142. /**
  143. * Sorting Algorithm Implementations
  144. */
  145. namespace sorts {
  146.     function swap(a: number[], i: number, j: number) {
  147.         let tmp = a[i];
  148.         a[i] = a[j];
  149.         a[j] = tmp;
  150.         pause(pauseDuration);
  151.     }
  152.     function compare(a: number, b: number) {
  153.         pause(pauseDuration)
  154.         return a < b;
  155.     }
  156.     export function insertionSort(a: number[]) {
  157.         for (let i = 0; i < a.length; i++) {
  158.             let value = a[i]
  159.             let j: number;
  160.             for (j = i - 1; j > -1 && compare(value, a[j]); --j) {
  161.                 a[j + 1] = a[j];
  162.                 pause(pauseDuration);
  163.             }
  164.             a[j + 1] = value;
  165.         }
  166.         return a;
  167.     }
  168.     export function selectionSort(a: number[]) {
  169.         for (let i = 0; i < a.length; i++) {
  170.             let min = i;
  171.             for (let j = i + 1; j < a.length; j++) {
  172.                 if (compare(a[j], a[min])) {
  173.                     min = j;
  174.                     pause(pauseDuration);
  175.                 }
  176.             }
  177.             if (i !== min) {
  178.                 swap(a, i, min);
  179.             }
  180.         }
  181.         return a;
  182.     }
  183.     export function bubbleSort(a: number[]) {
  184.         for (let i = 0; i < a.length; ++i) {
  185.             for (let j = 0; j < i; ++j) {
  186.                 if (compare(a[i], a[j])) {
  187.                     swap(a, i, j);
  188.                 }
  189.             }
  190.         }
  191.         return a;
  192.     }
  193.     export function shellSort(a: number[]) {
  194.         let increment = a.length / 2;
  195.         while (increment > 0) {
  196.             for (let i = increment; i < a.length; ++i) {
  197.                 let j = i;
  198.                 let t = a[i];
  199.                 while (j >= increment && compare(t, a[j - increment])) {
  200.                     a[j] = a[j - increment];
  201.                     j = j - increment;
  202.                     pause(pauseDuration);
  203.                 }
  204.                 a[j] = t;
  205.             }
  206.             if (increment == 2) {
  207.                 increment = 1;
  208.             } else {
  209.                 increment = Math.floor(increment * 5 / 11);
  210.             }
  211.         }
  212.         return a;
  213.     }
  214.     export function quickSort(a: number[]) {
  215.         qsort(a, 0, a.length - 1);
  216.         return a;
  217.         function qsort(a: number[], lo: number, hi: number) {
  218.             if (lo < hi) {
  219.                 let p = partition(a, lo, hi);
  220.                 qsort(a, lo, p - 1);
  221.                 qsort(a, p + 1, hi);
  222.             }
  223.         }
  224.         function partition(a: number[], lo: number, hi: number) {
  225.             let pivot = a[hi];
  226.             let i = lo - 1;
  227.             for (let j = lo; compare(j, hi); ++j) {
  228.                 if (a[j] < pivot) {
  229.                     i++;
  230.                     swap(a, i, j);
  231.                 }
  232.             }
  233.             swap(a, i + 1, hi);
  234.             return i + 1;
  235.         }
  236.     }
  237.     export function heapSort(a: number[]) {
  238.         function buildMaxHeap(a: number[]) {
  239.             let i = Math.floor(a.length / 2 - 1);
  240.             while (i >= 0) {
  241.                 heapify(a, i, a.length);
  242.                 i -= 1;
  243.             }
  244.         }
  245.         function heapify(heap: number[], i: number, max: number) {
  246.             while (i < max) {
  247.                 const left = 2 * i + 1;
  248.                 const right = left + 1;
  249.                 let curr = i;
  250.                 if (left < max && compare(heap[curr], heap[left])) {
  251.                     curr = left;
  252.                 }
  253.                 if (right < max && compare(heap[curr], heap[right])) {
  254.                     curr = right;
  255.                 }
  256.                 if (curr == i) return;
  257.                 swap(heap, i, curr);
  258.                 i = curr;
  259.             }
  260.         }
  261.         buildMaxHeap(a);
  262.         for (let i = a.length - 1; i > 0; --i) {
  263.             swap(a, 0, i);
  264.             heapify(a, 0, i);
  265.         }
  266.         return a;
  267.     }
  268.     export function mergeSort(a: number[]) {
  269.         // Typically, you wouldn't keep an 'offset' or a link to the 'original' array,
  270.         // as the sort works by returning a new, sorted array as output - not by modifying
  271.         // the one passed as input. Here, though, it is needed so that the preview on the
  272.         // screen can be updated
  273.         function msort(a: number[], offset: number, original: number[]): number[] {
  274.             if (a.length < 2) {
  275.                 return a;
  276.             }
  277.             const middle = Math.floor(a.length / 2);
  278.             let left = a.slice(0, middle);
  279.             let right = a.slice(middle, a.length);
  280.             left = msort(left, offset, original);
  281.             right = msort(right, offset + middle, original);
  282.             const merged = merge(left, right);
  283.             // Update preview on screen
  284.             merged.forEach(function (value: number, index: number) {
  285.                 original[offset + index] = value;
  286.                 pause(pauseDuration);
  287.             });
  288.             return merged;
  289.         }
  290.         function merge(left: number[], right: number[]) {
  291.             let result = [];
  292.             let lIndex = 0;
  293.             let rIndex = 0;
  294.             while (lIndex < left.length && rIndex < right.length) {
  295.                 if (compare(left[lIndex], right[rIndex])) {
  296.                     result.push(left[lIndex]);
  297.                     ++lIndex;
  298.                 } else {
  299.                     result.push(right[rIndex]);
  300.                     ++rIndex;
  301.                 }
  302.             }
  303.             while (lIndex < left.length) {
  304.                 result.push(left[lIndex]);
  305.                 ++lIndex;
  306.             }
  307.             while (rIndex < right.length) {
  308.                 result.push(right[rIndex]);
  309.                 ++rIndex;
  310.             }
  311.             return result;
  312.         }
  313.         return msort(a, 0, a);
  314.     }
  315.     export function isSorted(a: number[]) {
  316.         for (let i = 1; i < a.length; ++i) {
  317.             if (a[i - 1] > a[i]) {
  318.                 return false;
  319.             }
  320.         }
  321.         return true;
  322.     };
  323. }
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 07:11

【花雕动手做】基于 Kitronik 可编程开发板之排序算法

ARCADE MakeCode 排序算法可视化工具代码解读
这是一个基于ARCADE MakeCode的排序算法可视化工具,可以同时比较多种排序算法的性能。

1. 基本设置和数据结构
javascript
  1. const pauseDuration = 10;  // 每次操作后的暂停时间,用于可视化
  2. interface SortingAlgorithm {
  3.     title: string;        // 算法名称
  4.     algorithm: (values: number[]) => number[];  // 排序函数
  5.     a?: number[];         // 待排序的数组
  6.     place?: string;       // 排名(如"1st")
  7. }
  8. let currCount = 26;       // 当前数组元素数量
  9. let currentRun = 0;       // 当前运行次数标识
  10. let ySegment: number;     // 每个算法在屏幕上的垂直分段高度
  11. let currentPlace: number; // 当前排名
  12. let running: SortingAlgorithm[] = [];    // 正在运行的算法
  13. let notRunning: SortingAlgorithm[] = []; // 未运行的算法
复制代码


2. 添加排序算法示例
javascript
  1. addExample("selection sort", sorts.selectionSort);
  2. addExample("insertion sort", sorts.insertionSort);
  3. addExample("bubble sort", sorts.bubbleSort);
  4. addExample("shell sort", sorts.shellSort);
  5. addExample("heap sort", sorts.heapSort);
  6. addExample("quick sort", sorts.quickSort);
  7. addExample("merge sort", sorts.mergeSort);
复制代码


3. 初始化运行算法
javascript
  1. // 开始时随机选择两个算法运行
  2. for (let i = 0; i < 2; i++) {
  3.     moveRandom(notRunning, running);
  4. }
复制代码


4. 绘制函数
javascript
  1. game.onPaint(() => {
  2.     running.forEach(function (value: SortingAlgorithm, index: number) {
  3.         drawCurrentState(value, currCount, ySegment, index * ySegment);
  4.     });
  5. });
复制代码


5. 控制器事件处理
javascript
  1. // A按钮:重新开始
  2. controller.A.onEvent(ControllerButtonEvent.Pressed, () => {
  3.     start();
  4. });
  5. // 左键:移除一个排序算法
  6. controller.left.onEvent(ControllerButtonEvent.Pressed, () => {
  7.     if (running.length > 1) {
  8.         moveRandom(running, notRunning)
  9.         start();
  10.     }
  11. });
  12. // 右键:添加一个排序算法
  13. controller.right.onEvent(ControllerButtonEvent.Pressed, () => {
  14.     if (notRunning.length > 0) {
  15.         moveRandom(notRunning, running)
  16.         start();
  17.     }
  18. });
  19. // 上键:增加元素数量
  20. controller.up.onEvent(ControllerButtonEvent.Pressed, function () {
  21.     if (currCount + 6 < screen.width / 2) {
  22.         currCount += 6;
  23.         start();
  24.     }
  25. });
  26. // 下键:减少元素数量
  27. controller.down.onEvent(ControllerButtonEvent.Pressed, function () {
  28.     if (currCount > 6) {
  29.         currCount -= 6;
  30.         start();
  31.     }
  32. })
复制代码


6. 核心函数
移动随机元素函数
javascript
  1. function moveRandom<T>(a: T[], b: T[]) {
  2.     if (a.length > 0) {
  3.         const i = randint(0, a.length - 1);
  4.         b.push(a.removeAt(i));
  5.     }
  6. }
复制代码

添加示例函数
javascript

  1. <span style="background-color: rgb(255, 255, 255);">f</span>unction addExample(title: string, sortAlgorithm: (values: number[]) => number[]) {
  2.     let output: SortingAlgorithm = {
  3.         title: title,
  4.         algorithm: sortAlgorithm
  5.     }
  6.     notRunning.push(output);
  7. }
复制代码

启动函数
javascript
  1. function start() {
  2.     const r = new Math.FastRandom();
  3.     ++currentRun;  // 增加运行次数标识
  4.     currentPlace = 1;
  5.     ySegment = Math.floor(screen.height / running.length);
  6.     // 清除旧数组
  7.     running.forEach(v => {
  8.         while (v.a && v.a.length != 0)
  9.             v.a.pop();
  10.     });
  11.     // 创建新数组
  12.     running.forEach(v => v.a = fillWithDefault(r, currCount, ySegment - (image.font5.charHeight + 2)));
  13.     // 并行运行所有算法
  14.     running.forEach(v => control.runInParallel(() => {
  15.         const run = currentRun;
  16.         v.place = undefined;
  17.         v.algorithm(v.a);  // 执行排序算法
  18.         if (run === currentRun) {  // 确保是当前运行
  19.             const place = currentPlace++;
  20.             if (place === 1)
  21.                 music.powerUp.play();  // 第一名音效
  22.             else if (place === running.length)
  23.                 music.wawawawaa.play();  // 最后一名音效
  24.             v.place = place + ordinalIndicator(place);  // 设置排名
  25.         }
  26.     }));
  27. }
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 07:17

【花雕动手做】基于 Kitronik 可编程开发板之排序算法

排序算法解读
1、插入排序 (Insertion Sort)
javascript
  1. export function insertionSort(a: number[]) {
  2.     for (let i = 0; i < a.length; i++) {
  3.         let value = a[i]
  4.         let j: number;
  5.         // 将当前元素与已排序部分比较,找到合适位置插入
  6.         for (j = i - 1; j > -1 && compare(value, a[j]); --j) {
  7.             a[j + 1] = a[j];  // 向后移动元素
  8.             pause(pauseDuration);
  9.         }
  10.         a[j + 1] = value;  // 插入到正确位置
  11.     }
  12.     return a;
  13. }
复制代码

工作原理:将数组分为已排序和未排序两部分,逐个将未排序元素插入到已排序部分的正确位置

时间复杂度:最好O(n),平均O(n²),最坏O(n²)

空间复杂度:O(1)

特点:对小规模数据高效,稳定排序算法

2、选择排序 (Selection Sort)
javascript
  1. export function selectionSort(a: number[]) {
  2.     for (let i = 0; i < a.length; i++) {
  3.         let min = i;  // 假设当前位置是最小值
  4.         // 在未排序部分寻找最小值
  5.         for (let j = i + 1; j < a.length; j++) {
  6.             if (compare(a[j], a[min])) {
  7.                 min = j;  // 更新最小值位置
  8.                 pause(pauseDuration);
  9.             }
  10.         }
  11.         if (i !== min) {
  12.             swap(a, i, min);  // 将最小值放到已排序末尾
  13.         }
  14.     }
  15.     return a;
  16. }
复制代码

工作原理:每次从未排序部分选择最小元素,放到已排序部分的末尾

时间复杂度:始终为O(n²)

空间复杂度:O(1)

特点:简单但效率低,不稳定排序算法

3、冒泡排序 (Bubble Sort)
javascript
  1. export function bubbleSort(a: number[]) {
  2.     for (let i = 0; i < a.length; ++i) {
  3.         for (let j = 0; j < i; ++j) {
  4.             // 比较相邻元素,如果顺序错误则交换
  5.             if (compare(a[i], a[j])) {
  6.                 swap(a, i, j);
  7.             }
  8.         }
  9.     }
  10.     return a;
  11. }
复制代码

工作原理:重复遍历数组,比较相邻元素并交换,直到没有需要交换的元素

时间复杂度:最好O(n),平均O(n²),最坏O(n²)

空间复杂度:O(1)

特点:简单但效率低,稳定排序算法

4、希尔排序 (Shell Sort)
javascript
  1. export function shellSort(a: number[]) {
  2.     let increment = a.length / 2;  // 初始间隔
  3.     while (increment > 0) {
  4.         // 对各个子数组进行插入排序
  5.         for (let i = increment; i < a.length; ++i) {
  6.             let j = i;
  7.             let t = a[i];
  8.             // 对子数组进行插入排序
  9.             while (j >= increment && compare(t, a[j - increment])) {
  10.                 a[j] = a[j - increment];
  11.                 j = j - increment;
  12.                 pause(pauseDuration);
  13.             }
  14.             a[j] = t;
  15.         }
  16.         // 减小间隔
  17.         if (increment == 2) {
  18.             increment = 1;
  19.         } else {
  20.             increment = Math.floor(increment * 5 / 11);  // 使用特定序列减少间隔
  21.         }
  22.     }
  23.     return a;
  24. }
复制代码

工作原理:是插入排序的改进版,通过将数组分成多个子数组进行排序,逐渐减少子数组的间隔

时间复杂度:取决于间隔序列,最好O(n log n),最坏O(n²)

空间复杂度:O(1)

特点:比插入排序高效,不稳定排序算法

5、快速排序 (Quick Sort)
javascript
  1. export function quickSort(a: number[]) {
  2.     qsort(a, 0, a.length - 1);  // 递归排序
  3.     return a;
  4.     function qsort(a: number[], lo: number, hi: number) {
  5.         if (lo < hi) {
  6.             let p = partition(a, lo, hi);  // 分区操作
  7.             qsort(a, lo, p - 1);  // 递归排序左半部分
  8.             qsort(a, p + 1, hi);  // 递归排序右半部分
  9.         }
  10.     }
  11.     function partition(a: number[], lo: number, hi: number) {
  12.         let pivot = a[hi];  // 选择最后一个元素作为基准
  13.         let i = lo - 1;
  14.         for (let j = lo; compare(j, hi); ++j) {
  15.             if (a[j] < pivot) {
  16.                 i++;
  17.                 swap(a, i, j);  // 将小于基准的元素移到左边
  18.             }
  19.         }
  20.         swap(a, i + 1, hi);  // 将基准放到正确位置
  21.         return i + 1;
  22.     }
  23. }
复制代码

工作原理:分治算法,选择一个基准元素,将数组分成两部分,一部分小于基准,一部分大于基准,然后递归排序

时间复杂度:最好O(n log n),平均O(n log n),最坏O(n²)

空间复杂度:O(log n)

特点:通常是最快的排序算法,但不稳定

6、堆排序 (Heap Sort)
javascript
  1. export function heapSort(a: number[]) {
  2.     function buildMaxHeap(a: number[]) {
  3.         let i = Math.floor(a.length / 2 - 1);
  4.         // 从最后一个非叶子节点开始构建最大堆
  5.         while (i >= 0) {
  6.             heapify(a, i, a.length);
  7.             i -= 1;
  8.         }
  9.     }
  10.     function heapify(heap: number[], i: number, max: number) {
  11.         while (i < max) {
  12.             const left = 2 * i + 1;  // 左子节点
  13.             const right = left + 1;  // 右子节点
  14.             let curr = i;
  15.             // 找出当前节点、左子节点、右子节点中的最大值
  16.             if (left < max && compare(heap[curr], heap[left])) {
  17.                 curr = left;
  18.             }
  19.             if (right < max && compare(heap[curr], heap[right])) {
  20.                 curr = right;
  21.             }
  22.             if (curr == i) return;  // 如果当前节点已经是最大值,则返回
  23.             swap(heap, i, curr);  // 交换当前节点与最大值节点
  24.             i = curr;  // 继续向下调整
  25.         }
  26.     }
  27.    
  28.     buildMaxHeap(a);  // 构建最大堆
  29.     // 逐个提取最大值并放到数组末尾
  30.     for (let i = a.length - 1; i > 0; --i) {
  31.         swap(a, 0, i);  // 将最大值(堆顶)与末尾元素交换
  32.         heapify(a, 0, i);  // 调整堆
  33.     }
  34.     return a;
  35. }
复制代码

工作原理:利用堆数据结构,首先构建最大堆,然后逐个提取最大值并放到数组末尾

时间复杂度:始终为O(n log n)

空间复杂度:O(1)

特点:时间复杂度稳定,但不稳定排序算法

7、归并排序 (Merge Sort)
javascript
  1. export function mergeSort(a: number[]) {
  2.     function msort(a: number[], offset: number, original: number[]): number[] {
  3.         if (a.length < 2) {
  4.             return a;  // 基线条件:数组长度为1或0时已排序
  5.         }
  6.         const middle = Math.floor(a.length / 2);  // 找到中间位置
  7.         let left = a.slice(0, middle);  // 分割左半部分
  8.         let right = a.slice(middle, a.length);  // 分割右半部分
  9.         left = msort(left, offset, original);  // 递归排序左半部分
  10.         right = msort(right, offset + middle, original);  // 递归排序右半部分
  11.         const merged = merge(left, right);  // 合并两个已排序数组
  12.         // 更新屏幕上的可视化效果
  13.         merged.forEach(function (value: number, index: number) {
  14.             original[offset + index] = value;
  15.             pause(pauseDuration);
  16.         });
  17.         return merged;
  18.     }
  19.     function merge(left: number[], right: number[]) {
  20.         let result = [];
  21.         let lIndex = 0;
  22.         let rIndex = 0;
  23.         // 比较两个数组的元素,按顺序合并
  24.         while (lIndex < left.length && rIndex < right.length) {
  25.             if (compare(left[lIndex], right[rIndex])) {
  26.                 result.push(left[lIndex]);
  27.                 ++lIndex;
  28.             } else {
  29.                 result.push(right[rIndex]);
  30.                 ++rIndex;
  31.             }
  32.         }
  33.         // 将剩余元素添加到结果中
  34.         while (lIndex < left.length) {
  35.             result.push(left[lIndex]);
  36.             ++lIndex;
  37.         }
  38.         while (rIndex < right.length) {
  39.             result.push(right[rIndex]);
  40.             ++rIndex;
  41.         }
  42.         return result;
  43.     }
  44.     return msort(a, 0, a);
  45. }
复制代码

工作原理:分治算法,将数组分成两半,递归排序,然后合并两个已排序的子数组

时间复杂度:始终为O(n log n)

空间复杂度:O(n)

特点:稳定排序算法,适合大数据集,但需要额外空间

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 07:22

【花雕动手做】基于 Kitronik 可编程开发板之排序算法

通过模拟器,调试与模拟运行

【花雕动手做】基于 Kitronik 可编程开发板之排序算法图1

实验场景记录

【花雕动手做】基于 Kitronik 可编程开发板之排序算法图3

【花雕动手做】基于 Kitronik 可编程开发板之排序算法图4

【花雕动手做】基于 Kitronik 可编程开发板之排序算法图5

【花雕动手做】基于 Kitronik 可编程开发板之排序算法图6

【花雕动手做】基于 Kitronik 可编程开发板之排序算法图7

【花雕动手做】基于 Kitronik 可编程开发板之排序算法图2

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 07:25

【花雕动手做】基于 Kitronik 可编程开发板之排序算法

【花雕动手做】基于 Kitronik 可编程开发板之排序算法图1
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail