直接插入排序(Insertion Sort)是一种简单的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序)。
步骤:
从第一个元素开始,该元素可以认为已经被排序。
取出下一个元素,在已经排序的元素序列中从后向前扫描。
如果该元素(已排序)大于新元素,将该元素移到下一位置。
重复步骤3,直到找到已排序的元素小于或者等于新元素的位置。
将新元素插入到该位置后。
重复步骤2~5。
以下是直接插入排序的一个示例(以升序排序为例):
初始序列:[49, 38, 65, 97, 76, 13, 27, 49]
第一次排序:[38, 49, 65, 97, 76, 13, 27, 49]
解释:将49作为已排序序列,38比49小,所以将38插入到49前面。
第二次排序:[38, 49, 65, 97, 76, 13, 27, 49]
解释:49已经在正确的位置,所以序列不变。
第三次排序:[38, 49, 65, 97, 76, 13, 27, 49]
解释:65比49大,所以65保持在49后面。
...
最终排序:[13, 27, 38, 49, 49, 65, 76, 97]
#include <iostream>
#include <vector>
// 直接插入排序函数
void insertionSort(std::vector<int>& arr) {
int i, j, key;
for (i = 1; i < arr.size(); i++) { // 从第二个元素开始遍历数组
key = arr[i]; // 当前要插入的元素
j = i - 1;
// 将大于key的元素向后移动
while (j >= 0 && arr[j] > key) { // 寻找插入位置
arr[j + 1] = arr[j]; // 向后移动元素
j = j - 1; // 继续向前比较
}
arr[j + 1] = key; // 插入key到正确的位置
}
}
// 打印数组函数
void printArray(const std::vector<int>& arr) {
for (int num : arr) {
std::cout << num << " ";
}
std::cout << std::endl;
}
// 主函数
int main() {
std::vector<int> arr = {49, 38, 65, 97, 76, 13, 27, 49};
std::cout << "Original array:\n";
printArray(arr);
insertionSort(arr); // 调用插入排序函数进行一次完整的排序
std::cout << "Final sorted array:\n";
printArray(arr);
return 0;
}
直接插入排序的时间复杂度在最坏情况下是O(n^2),在最好情况下(即输入序列已经是有序的)是O(n)。尽管它的效率在处理小数据集时相对较高,但当数据集较大时,其效率会显著下降。
下面我用大白话来给你讲解一下直接插入排序。
想象一下你手里有一副扑克牌,你已经把前面的几张牌排好序了,现在你每摸一张新牌,就要把它插入到前面已经排好序的牌中合适的位置,使得整副牌始终是有序的。这个过程就是直接插入排序。
具体步骤如下:
假设你手里已经有几张牌排好序了,比如是3、5、8、10,现在你摸到了一张新牌,是6。
你从最后一张排好序的牌(10)开始比较,发现6比10小,所以你把10往后移一个位置。
接着比较6和8,6还是比8小,所以你再把8往后移一个位置。
然后比较6和5,6比5大,所以你找到了6应该插入的位置,就在5的后面。
你把6放到5和8之间,现在手里的牌变成了3、5、6、8、10,依然是排好序的。
你重复这个过程,每次摸一张新牌,就把它插入到前面已经排好序的牌中的合适位置。
这个过程就像你往一个已经排好队的队伍里插入一个人,你从队伍的最后开始,一个一个比较,直到找到这个人应该站的位置,然后把他放进去。
直接插入排序就是这样,简单但是有点慢,特别是当你手里的牌(或者队伍里的人)很多的时候,你就要比较很多次,才能找到新牌(或者新人)应该放的位置。所以,如果有很多数据要排序,直接插入排序可能就不是最快的办法了。