序言
心若有阳光,你便会看见这个世界有那么多美好值得期待和向往。
决定开一个算法专栏,希望能帮助大家很好的了解算法。主要深入解析每个算法,从概念到示例。
我们一起努力,成为更好的自己!
今天第1讲,讲一下排序算法的---冒泡排序算法
一、算法介绍
冒泡排序(Bubble Sort)是一种简单的排序算法,它重复地遍历要排序的列表,一次比较两个元素,并且如果它们的顺序错误就交换它们。遍历的过程持续多次,每一轮都会将未排序部分的最大元素浮动到最右侧。这个过程像气泡一样逐步上浮,因此得名"冒泡排序"。
1.1 原理介绍
冒泡排序算法通过多次遍历未排序部分,比较并交换相邻元素,将最大值逐步移动至右侧,实现对整个列表的排序。
下面是冒泡排序的基本步骤:
-
比较相邻元素: 从列表的第一个元素开始,依次比较相邻的两个元素,如果它们的顺序是错误的(比如,前面的元素大于后面的元素),则交换它们。
-
一轮遍历: 重复第一步,直到整个列表都被遍历一次。在这一轮的遍历过程中,最大的元素就像气泡一样浮到了最右侧。
-
重复: 重复以上两个步骤,每一轮都会把未排序部分的最大元素浮动到正确的位置。未排序部分逐渐减小,直到整个列表排序完成。
这个过程可以形象地理解为气泡上浮的过程,因为每一轮排序都会使一个最大的元素"浮"到正确的位置。
下面通过一个简单的示意图来图解冒泡排序算法的过程:
考虑要排序的列表:[5, 3, 8, 4, 2]
初始状态:
csharp
[5, 3, 8, 4, 2]
第一轮遍历:
比较并交换相邻元素,将最大值冒泡到右侧:
csharp
[3, 5, 4, 2, 8]
第二轮遍历:
继续比较并交换相邻元素:
csharp
[3, 4, 2, 5, 8]
第三轮遍历:
再次比较并交换:
csharp
[3, 2, 4, 5, 8]
第四轮遍历:
最终得到排序后的列表:
csharp
[2, 3, 4, 5, 8]
这个过程就好像气泡逐渐上浮的过程一样,最大的元素被依次交换到正确的位置,最终实现整个列表的升序排序。
1.2 优缺点
优点:
-
简单易懂: 冒泡排序的实现非常简单,易于理解和实现,适合初学者学习排序算法的入门。
-
空间复杂度低: 冒泡排序是一种原地排序算法,不需要额外的存储空间,只需要少量辅助变量,因此空间复杂度较低。
缺点:
-
性能较差: 冒泡排序的时间复杂度为O(n^2),其中n是待排序元素的数量。这使得它在处理大型数据集时效率较低,不适合大规模数据排序。
-
不稳定性: 在相邻元素相等时,冒泡排序可能会交换它们的位置,导致相同元素的相对位置发生改变,因此它是一种不稳定的排序算法。
-
适用场景受限: 冒泡排序适用于少量元素的情况,对于大规模数据集,更高效的排序算法如快速排序、归并排序等更为适用。
-
比较次数较多: 冒泡排序每一轮都要比较相邻元素的大小,并可能进行交换,导致比较次数较多,尤其是在已经有序的情况下,仍然需要进行多轮比较。
1.3 复杂度
时间复杂度:
-
冒泡排序的时间复杂度取决于元素的数量和列表的初始顺序。在最坏情况下,冒泡排序需要进行n×(n−1)/2 次比较和交换操作,其中n是待排序元素的数量。因此,冒泡排序的最坏时间复杂度是O(n2)。
-
在最好的情况下,如果列表已经是有序的,冒泡排序只需要进行一轮遍历,进行n−1 次比较,但没有交换操作。此时的最好时间复杂度是O(n)。然而,由于冒泡排序每轮都要进行比较,即使在最好情况下,它的比较次数也较多。
-
平均情况下,冒泡排序的时间复杂度仍然是O(n2)。这使得冒泡排序在处理大规模数据时性能较差,不如一些更为高效的排序算法。
空间复杂度:
冒泡排序是一种原地排序算法,它不需要额外的存储空间,只需要少量辅助变量。因此,冒泡排序的空间复杂度是O(1)。
1.4 使用场景
以下是一些冒泡排序适用的场景:
-
小规模数据: 冒泡排序适用于小规模数据集的排序。在数据量较小时,冒泡排序的简单实现可能比更复杂的排序算法更容易理解和实现。
-
教学和学习: 由于其简单直观的原理,冒泡排序常常用于教学和学习排序算法。它为学习者提供了一个入门级别的算法,用于理解排序的基本概念。
-
已基本有序的数据: 如果输入数据已经基本有序,冒泡排序的性能可能比较好。因为冒泡排序每次只会比较相邻元素,若列表已经接近有序状态,则只需要少量的遍历就能完成排序。
-
适用于部分排序: 如果只需要对列表的一部分元素进行排序,而不是整个列表,冒泡排序可能比其他算法更具竞争力。它可以提前终止,一旦发现列表已经有序,就无需进行额外的比较和交换。
二、代码实现
2.1 Java代码实现
2.1.1 代码示例
ini
public class BubbleSort {
// 冒泡排序函数
public static void bubbleSort(int[] array) {
int n = array.length;
// 外层循环控制轮数,每一轮都会将一个最大元素冒泡到最右侧
for (int i = 0; i < n - 1; i++) {
// 内层循环负责相邻元素的比较和交换
// 注意内层循环每轮都会将一个未排序部分的最大元素浮动到最右侧
for (int j = 0; j < n - i - 1; j++) {
// 比较相邻元素,如果顺序错误则交换
if (array[j] > array[j + 1]) {
// 交换array[j]和array[j + 1]
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
public static void main(String[] args) {
// 示例数组
int[] arr = {64, 34, 25, 12, 22, 11, 90};
System.out.println("原始数组:");
printArray(arr);
// 调用冒泡排序算法
bubbleSort(arr);
System.out.println("\n排序后的数组:");
printArray(arr);
}
// 辅助函数,用于打印数组
public static void printArray(int[] array) {
int n = array.length;
for (int i = 0; i < n; ++i) {
System.out.print(array[i] + " ");
}
System.out.println();
}
}
2.1.2 代码详解
bubbleSort
函数实现了冒泡排序算法,其中外层循环控制排序的轮数,内层循环负责相邻元素的比较和交换。
main
函数中创建了一个示例数组,调用了bubbleSort
进行排序,然后打印排序前和排序后的数组。
printArray
函数用于打印数组内容,方便观察算法执行结果。
这个代码示例展示了冒泡排序的基本实现,可以通过调用 bubbleSort
函数对需要排序的数组进行排序。
2.1.3 运行结果
2.2 Python代码实现
2.2.1 代码示例
python
def bubble_sort(arr):
"""
冒泡排序算法实现
Parameters:
- arr: 待排序的数组
Returns:
- None(原地排序,直接修改输入数组)
"""
n = len(arr)
# 外层循环控制轮数,每一轮都会将一个最大元素冒泡到最右侧
for i in range(n - 1):
# 内层循环负责相邻元素的比较和交换
# 注意内层循环每轮都会将一个未排序部分的最大元素浮动到最右侧
for j in range(n - i - 1):
# 比较相邻元素,如果顺序错误则交换
if arr[j] > arr[j + 1]:
# 交换arr[j]和arr[j + 1]
arr[j], arr[j + 1] = arr[j + 1], arr[j]
# 示例数组
arr = [64, 34, 25, 12, 22, 11, 90]
print("原始数组:")
print(arr)
# 调用冒泡排序算法
bubble_sort(arr)
print("\n排序后的数组:")
print(arr)
2.2.2 代码详解
代码中有以下几个关键点:
bubble_sort
函数实现了冒泡排序算法,其中外层循环控制排序的轮数,内层循环负责相邻元素的比较和交换。示例数组
arr
包含了需要排序的数据。调用
bubble_sort
函数对示例数组进行排序。打印排序前和排序后的数组,观察算法执行结果。
这个Python代码示例展示了冒泡排序的基本实现,通过调用 bubble_sort
函数可以对需要排序的数组进行排序。
2.2.3 运行结果
好啦,今天就到这里啦,下期见喽~~🙉