============================================================================================================================================================================
序言
你只管努力,其他交给时间,时间会证明一切。
决定开一个算法专栏,希望能帮助大家很好的了解算法。主要深入解析每个算法,从概念到示例。
我们一起努力,成为更好的自己!
今天第二讲,讲一下排序算法的插入排序
一、算法介绍
1.1 原理介绍
插入排序是一种简单直观的排序算法,它的基本思想是将一个元素插入到已经排好序的部分数组中,从而逐步扩大有序部分。
详细一点解释:
是将一个数组分成已排序和未排序两部分,初始时已排序部分只有一个元素,然后将未排序部分的每个元素插入到已排序部分的适当位置,直到所有元素都被排序。
当将一个元素插入到已排序部分时,需要将已排序部分中所有大于该元素的元素向后移动一位,然后将该元素插入到合适的位置。
具体实现时,可以使用两个嵌套的循环。外层循环遍历未排序部分中的每个元素,内层循环从待插入元素的前一个位置开始,向前遍历已排序部分,直到找到第一个小于等于待插入元素的位置,然后将待插入元素插入到该位置之后。
下面是一个伪代码实现:
css
for i from 1 to n-1 do
j = i
while j > 0 and A[j-1] > A[j] do
swap A[j] and A[j-1]
j = j - 1
其中,变量 i 用于遍历未排序部分,变量 j 指向待插入元素在已排序部分中的位置,循环内部的 while 循环用于将待插入元素插入到正确的位置。
举个例子
下面通过一个简单的例子来图解插入排序的过程。
考虑数组 [5, 2, 4, 6, 1, 3]
,我们将逐步对其进行插入排序:
初始状态:
csharp
[5, 2, 4, 6, 1, 3]
第一轮:
将第二个元素 2
插入到已排序部分 [5]
中,得到 [2, 5, 4, 6, 1, 3]
。
csharp
[2, 5, 4, 6, 1, 3]
第二轮:
将第三个元素 4
插入到已排序部分 [2, 5]
中,得到 [2, 4, 5, 6, 1, 3]
。
csharp
[2, 4, 5, 6, 1, 3]
第三轮:
将第四个元素 6
插入到已排序部分 [2, 4, 5]
中,得到 [2, 4, 5, 6, 1, 3]
。
csharp
[2, 4, 5, 6, 1, 3]
第四轮:
将第五个元素 1
插入到已排序部分 [2, 4, 5, 6]
中,得到 [1, 2, 4, 5, 6, 3]
。
csharp
[1, 2, 4, 5, 6, 3]
第五轮:
将最后一个元素 3
插入到已排序部分 [1, 2, 4, 5, 6]
中,得到 [1, 2, 3, 4, 5, 6]
。
csharp
[1, 2, 3, 4, 5, 6]
最终,数组已经排好序。每一轮都是将一个元素插入到有序的部分,逐步扩大有序部分,直到整个数组有序。这就是插入排序的基本过程。
动图示例
1.2 优缺点
优点:
-
简单易理解: 插入排序的实现非常简单,容易理解,适用于初学者学习算法的入门。
-
稳定性: 插入排序是一种稳定的排序算法,相等元素的相对位置不会改变。
-
对小数据量有效: 在数据量较小的情况下,插入排序的性能通常比其他高级排序算法(如快速排序、归并排序)更好,因为其常数因子较小。
-
部分有序数组: 当数组中的数据接近有序状态时,插入排序的性能较好,因为插入的元素往往只需要移动较小的距离。
缺点:
-
时间复杂度较高: 插入排序的平均时间复杂度为O(n^2),在数据规模较大时,性能不如快速排序、归并排序等O(n log n)复杂度的排序算法。
-
对逆序数组效率低: 当数组完全逆序时,每次插入都需要移动大量元素,导致性能下降。
-
不适合大规模数据: 插入排序的性能在处理大规模数据时较差,不如一些更高效的排序算法。
-
不适合链表: 插入排序对于链表的操作相对较复杂,因为需要频繁修改指针指向,相比于数组实现,性能较差。
1.3 复杂度
时间复杂度为 O(n^2),空间复杂度为 O(1)。
1.4 使用场景
插入排序的优点是对于小规模的数据集,它的效率比较高,而且它的实现比较简单。
但是对于大规模的数据集,插入排序的效率会比较低,因为它需要进行大量的元素移动操作。
二、代码实现
2.1 Java代码实现
2.1.1 代码示例
scss
public class QuickSortExample {
public static void main(String[] args) {
int[] arr = {5, 2, 4, 6, 1, 3};
System.out.println("Original Array:");
printArray(arr);
quickSort(arr, 0, arr.length - 1);
System.out.println("Sorted Array:");
printArray(arr);
}
public static void quickSort(int[] arr, int left, int right) {
if (left >= right) {
return;
}
int pivot = arr[left];
int i = left + 1, j = right;
while (i <= j) {
if (arr[i] < pivot) {
i++;
} else if (arr[j] >= pivot) {
j--;
} else {
swap(arr, i, j);
i++;
j--;
}
}
swap(arr, left, j);
quickSort(arr, left, j - 1);
quickSort(arr, j + 1, right);
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
private static void printArray(int[] arr) {
for (int num : arr) {
System.out.print(num + " ");
}
System.out.println();
}
}
2.1.2 代码详解
实现思路:
首先检查左右指针的位置,如果左指针大于等于右指针,说明当前的子数组已经有序,直接返回即可。
否则,选择一个基准元素(这里选择左端点的元素作为基准),将数组分成两个部分,小于基准元素的部分和大于等于基准元素的部分。
然后,使用两个指针 i 和 j 分别从左右两端开始遍历,将小于基准元素的元素移动到左边,将大于等于基准元素的元素移动到右边,直到 i 和 j 相遇。
最后,将基准元素交换到正确的位置上,递归地对左右两个部分进行快速排序。
代码实现:
使用了两个辅助指针 i 和 j,分别从左右两端开始遍历数组。
在遍历过程中,如果 arr[i] 小于 pivot,就将 i 向右移动一位;如果 arr[j] 大于等于 pivot,就将 j 向左移动一位;
否则,交换 arr[i] 和 arr[j],然后将 i 向右移动一位,将 j 向左移动一位。当 i 和 j 相遇时,遍历结束,此时 arr[j] 是小于 pivot 的最后一个元素,将 pivot 交换到 arr[j] 的位置上,然后递归地对左右两个部分进行快速排序。
2.1.3 运行结果
javascript
Original Array:
5 2 4 6 1 3
Sorted Array:
1 2 3 4 5 6
2.2 Python代码实现
2.2.1 代码示例
ini
def quick_sort(arr):
if len(arr) <= 1:
return arr
else:
pivot = arr[0]
less_than_pivot = [x for x in arr[1:] if x <= pivot]
greater_than_pivot = [x for x in arr[1:] if x > pivot]
return quick_sort(less_than_pivot) + [pivot] + quick_sort(greater_than_pivot)
# 示例
if __name__ == "__main__":
input_array = [5, 2, 4, 6, 1, 3]
print("Original Array:")
print(input_array)
sorted_array = quick_sort(input_array)
print("Sorted Array:")
print(sorted_array)
2.2.2 代码详解
代码思路
首先检查数组的长度,如果长度小于等于 1,说明该数组已经有序,直接返回即可。
否则,选择一个基准元素(这里选择第一个元素作为基准),将数组分成两个部分,小于基准元素的部分和大于等于基准元素的部分。
然后,递归地对这两个部分进行快速排序,并将它们拼接起来,得到最终的排序结果。
代码实现:
使用了两个辅助数组 left 和 right,分别用于存储小于基准元素和大于等于基准元素的部分。
遍历原数组时,如果当前元素小于基准元素,就将它添加到 left 数组中,否则将它添加到 right 数组中。
最后,递归地对 left 和 right 数组进行排序,并将它们和基准元素拼接起来,得到最终的排序结果。
2.2.3 运行结果
csharp
Original Array:
[5, 2, 4, 6, 1, 3]
Sorted Array:
[1, 2, 3, 4, 5, 6]
今天就到这里了,下期见喽~