【金九银十】笔试通关 + 小学生都能学会的选择排序

请在此添加图片描述

算法原理

选择排序(Selection Sort)是一种简单的排序算法,它的核心思想是:在每一轮的排序中,从未排序的部分中找到最小(或最大)的元素,并将其放到已排序部分的末尾。

  1. 初始状态:数组被分为两部分,已排序部分和未排序部分。开始时,已排序部分为空,而未排序部分包含所有元素。
  2. 第一轮:从未排序部分中找到最小的元素,将其与未排序部分的第一个元素交换位置。这时,已排序部分包含了一个元素,即当前找到的最小元素。
  3. 第二轮:继续在剩下的未排序部分中找到最小元素,再将其与未排序部分的第一个元素交换。这时,已排序部分包含两个元素,且这两个元素是按顺序排列的。
  4. 重复上述步骤:不断重复这一过程,直到所有元素都被排序,未排序部分为空。

时间复杂度:选择排序的时间复杂度为 (O(n^2)),其中 (n) 是数组的元素数量。尽管它的效率不高,但由于其简单性和容易理解,选择排序在教学中广泛使用。

选择排序的概念可以追溯到20世纪40年代左右。随着计算机科学的发展,学者们开始研究如何让计算机高效地排列一组数据。虽然没有明确的记录显示选择排序由谁首先提出,但它与早期的排序算法(如冒泡排序)一起,成为了计算机科学的基础算法之一。

在最早的计算机上,存储和计算资源非常有限。算法设计的一个重要目标是尽可能减少交换操作,因为交换通常需要较多的资源。选择排序通过每轮只进行一次交换(在找出最小元素后),在这方面表现得相对高效。

选择排序的故事可以和早期的“打牌”经验联系在一起。想象你在玩纸牌时,需要对手中的牌进行排序。在没有其他人帮助的情况下,你可能会采取选择排序的策略:先找到手中最小的一张牌,把它放在最左边,然后继续在剩下的牌中找到最小的一张,放在左边的第二个位置,依此类推,直到手中的牌全部按从小到大的顺序排列好。

这种策略虽然简单,但也容易理解,特别适合资源有限的情况,如早期的计算机。随着计算机性能的提升和更多复杂算法的出现,选择排序逐渐被更高效的算法(如快速排序、归并排序)所取代,但它作为计算机科学教育中的经典算法,至今仍被广泛教授和使用。

过程分析

假设我们有一个数组 arr,内容为 [64, 25, 12, 22, 11],我们使用选择排序对其进行升序排列。过程如下:

初始状态

- 数组:`[64, 25, 12, 22, 11]`
- 已排序部分:`[]`
- 未排序部分:`[64, 25, 12, 22, 11]`

第一轮

- 在未排序部分 `[64, 25, 12, 22, 11]` 中找到最小值 `11`,与第一个元素 `64` 交换。
- 数组:`[11, 25, 12, 22, 64]`
- 已排序部分:`[11]`
- 未排序部分:`[25, 12, 22, 64]`

第二轮

- 在未排序部分 `[25, 12, 22, 64]` 中找到最小值 `12`,与第一个元素 `25` 交换。
- 数组:`[11, 12, 25, 22, 64]`
- 已排序部分:`[11, 12]`
- 未排序部分:`[25, 22, 64]`

第三轮

- 在未排序部分 `[25, 22, 64]` 中找到最小值 `22`,与第一个元素 `25` 交换。
- 数组:`[11, 12, 22, 25, 64]`
- 已排序部分:`[11, 12, 22]`
- 未排序部分:`[25, 64]`

第四轮

- 在未排序部分 `[25, 64]` 中找到最小值 `25`,无需交换,因为它已经在正确的位置。
- 数组:`[11, 12, 22, 25, 64]`
- 已排序部分:`[11, 12, 22, 25]`
- 未排序部分:`[64]`

第五轮

- 只剩下一个元素 `64`,它自动排序完成。
- 数组:`[11, 12, 22, 25, 64]`
- 已排序部分:`[11, 12, 22, 25, 64]`
- 未排序部分:`[]`

最终,数组从 [64, 25, 12, 22, 11] 排列成 [11, 12, 22, 25, 64],完成了选择排序的过程。

通过这个过程,我们可以清楚地看到每一步如何找到未排序部分的最小值,并将其放到正确的位置上,直到整个数组排序完毕。这种方法尽管简单,但非常直观,并且不需要大量的内存或复杂的操作,特别适合理解基本的排序概念。

动态实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Selection Sort Visualization</title>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            background-color: #f4f4f9;
            color: #333;
            margin: 0;
            padding: 20px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
        }

        h1 {
            color: #4CAF50;
            font-size: 2.5rem;
            margin-bottom: 20px;
        }

        .container {
            display: flex;
            justify-content: space-around;
            align-items: flex-end;
            width: 80%;
            max-width: 800px;
            background-color: #fff;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }

        .bar {
            width: 30px;
            margin-right: 4px;
            background-color: #1E90FF;
            border-radius: 5px 5px 0 0;
            transition: background-color 0.3s, transform 0.3s;
            display: flex;
            align-items: flex-end;
            justify-content: center;
            font-size: 0.8rem;
            color: white;
            padding-bottom: 5px;
        }

        .bar:hover {
            background-color: #4682B4;
            transform: scale(1.05);
        }

        button {
            margin-top: 20px;
            padding: 10px 20px;
            font-size: 1rem;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            transition: background-color 0.3s;
        }

        button:hover {
            background-color: #45a049;
        }
    </style>
</head>
<body>

    <h1>Selection Sort Visualization</h1>
    <div id="array" class="container"></div>
    <button onclick="selectionSort()">Start Sorting</button>

    <script>
        const array = [64, 25, 12, 22, 11];
        const container = document.getElementById('array');

        function renderArray(arr) {
            container.innerHTML = '';
            arr.forEach(value => {
                const bar = document.createElement('div');
                bar.classList.add('bar');
                bar.style.height = `${value * 3}px`;
                bar.textContent = value;
                container.appendChild(bar);
            });
        }

        async function selectionSort() {
            const arr = [...array];
            const n = arr.length;

            for (let i = 0; i < n - 1; i++) {
                let minIndex = i;

                for (let j = i + 1; j < n; j++) {
                    if (arr[j] < arr[minIndex]) {
                        minIndex = j;
                    }
                }

                if (minIndex !== i) {
                    [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
                    renderArray(arr);
                    await new Promise(resolve => setTimeout(resolve, 500)); // 等待 0.5 秒
                }
            }
        }

        renderArray(array);
    </script>

</body>
</html>

[外链图片转存中…(img-rz8Cw4F9-1728347963101)]

下面是对 selectionSort 函数中代码的详细解释:

async function selectionSort() {
    const arr = [...array];  // 创建数组的副本,避免直接修改原数组
    const n = arr.length;    // 获取数组的长度

    for (let i = 0; i < n - 1; i++) {  // 外层循环,控制选择排序的轮次
        let minIndex = i;  // 假设当前第 i 个元素是最小值,并将其索引存储在 minIndex 中

        for (let j = i + 1; j < n; j++) {  // 内层循环,遍历 i 后面的元素
            if (arr[j] < arr[minIndex]) {  // 如果找到比当前最小值还小的元素
                minIndex = j;  // 更新最小值的索引
            }
        }

        if (minIndex !== i) {  // 如果找到的最小值索引不是当前索引
            [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];  // 交换当前元素与找到的最小值
            renderArray(arr);  // 更新数组的可视化表示
            await new Promise(resolve => setTimeout(resolve, 500));  // 等待 0.5 秒,用于展示排序过程中的变化
        }
    }
}

代码解释

**const arr = …array;**这里使用了 …array 进行数组的浅拷贝。这样做的目的是创建一个 array 数组的副本,以防止原始数组在排序过程中被修改。这是为了确保原始数据的安全,同时能够自由操作副本进行排序。

**const n = arr.length;**这行代码获取数组的长度 n,后续将使用这个值来控制循环次数。

**外层循环 for (let i = 0; i < n - 1; i++) {}**这个循环控制了选择排序的轮次。每轮循环的目标是将数组的第 i 个元素设置为当前未排序部分的最小值。

**let minIndex = i;**假设当前第 i 个元素是未排序部分的最小值,并将 minIndex 变量设为当前索引 i。

**内层循环 for (let j = i + 1; j < n; j++) {}**这个循环从 i+1 开始遍历数组的剩余部分,用于寻找是否存在比 arri 更小的元素。如果找到更小的元素,则更新 minIndex 的值。

**if (arrj < arrminIndex) { minIndex = j; }**通过比较 arrj 和 arrminIndex,确定更小的元素。如果找到比当前最小值还小的元素,则更新 minIndex 的索引。

**if (minIndex !== i) { [arri, arrminIndex] = [arrminIndex, arri]; }**如果 minIndex 不等于 i,说明在剩余部分找到更小的元素,需要将其与当前元素 arri 进行交换。使用数组解构交换两个元素的位置。

**renderArray(arr);**调用 renderArray 函数,重新渲染数组的可视化表示,让用户看到当前数组的变化。

**await new Promise(resolve => setTimeout(resolve, 500));**这里使用了 await 和 Promise 的组合,延迟 0.5 秒后继续执行。这是为了让用户能清楚地看到每一步的排序过程。如果没有这个延迟,排序会瞬间完成,无法可视化。

总结

整个代码实现了选择排序算法的基本逻辑,并通过逐步更新数组的可视化表示,帮助用户理解排序过程。外层循环确保每次选择一个最小值放在正确位置,而内层循环在剩余未排序的部分中寻找最小值。通过异步延迟,用户可以逐步看到排序的每一步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不惑_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值