冒泡排序和选择排序的区别#
冒泡排序的基本思想是从待排序的序列中依次比较相邻的两个元素,如果它们的顺序不正确,则进行交换。通过多次遍历,将最大(或最小)的元素逐渐移动到序列的最后,直到整个序列有序为止。
选择排序的基本思想是从待排序的序列中选择最小(或最大)的元素,和序列的第一个元素进行交换,然后从剩余的未排序部分中继续选择最小(或最大)的元素,和序列的第二个元素进行交换,以此类推,直到整个序列有序为止。
总结起来,冒泡排序通过比较相邻元素并交换来逐步移动最大(或最小)元素,而选择排序则是通过选择最小(或最大)元素并交换来逐步构建有序序列。由于每次交换需要占用较多的时间,所以选择排序的平均性能要好于冒泡排序,但在实际应用中,如果待排序序列基本有序,冒泡排序可能会比选择排序更快。
选择排序和冒泡排序的时间复杂度和稳定性#
冒泡排序(Bubble Sort)
时间复杂度:最好情况下 O (n),平均和最坏情况下 O (n^2)。
空间复杂度:O (1)。
稳定性:是一个稳定的排序算法,因为在相邻元素交换的时候,只有当需要交换的元素之间的相对顺序不同时才会发生交换。
选择排序(Selection Sort):
时间复杂度:无论最好、平均和最坏情况下都是 O (n^2)。
空间复杂度:O (1)。
稳定性:选择排序是一个非稳定的排序算法。在每次选择最小(或最大)元素的过程中,可能会破坏相同元素之间的相对顺序。
综上所述,冒泡排序是一个稳定的排序算法,而选择排序是一个非稳定的排序算法。选择排序在每一轮选择最小(或最大)元素的过程中,可能导致相同元素的相对顺序发生改变。因此,在需要保持相同元素相对顺序的情况下,选择排序不适用,而冒泡排序可以保持相同元素的相对顺序。
Python 代码举例说明稳定性和非稳定性的区别,分别使用冒泡排序和选择排序来进行排序#
首先,我们定义一个包含姓名和分数属性的学生类:
python
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def __str__(self):
return f"{self.name}: {self.score}"
接下来,我们创建一个学生数组,并包含两个分数相等但姓名不同的学生对象:
students = [
Student("Tom", 80),
Student("Alice", 90),
Student("Bob", 80),
Student("Jack", 70),
Student("David", 80)
]
然后,我们分别使用冒泡排序和选择排序对学生数组按照分数进行排序:
冒泡排序:
def bubble_sort(students):
n = len(students)
for i in range(n - 1):
for j in range(n - 1 - i):
if students[j].score > students[j + 1].score:
students[j], students[j + 1] = students[j + 1], students[j]
bubble_sort(students)
选择排序:
def selection_sort(students):
n = len(students)
for i in range(n - 1):
min_index = i
for j in range(i + 1, n):
if students[j].score < students[min_index].score:
min_index = j
students[i], students[min_index] = students[min_index], students[i]
selection_sort(students)
最后,我们遍历排序后的学生数组,输出排序结果:
for student in students:
print(student)
如果采用稳定的排序算法,比如冒泡排序,执行上述代码后的输出可能是:
Jack: 70
Tom: 80
Bob: 80
David: 80
Alice: 90
可以看到,分数相同的学生对象在排序后保持了原有的相对顺序。
而如果采用非稳定的排序算法,比如选择排序,执行上述代码后的输出可能是:
Jack: 70
Bob: 80
David: 80
Tom: 80
Alice: 90
可以看到,选择排序打乱了分数相同的学生对象的相对顺序。
如果相同分数的元素之间存在某种关联性或排序规则,改变它们的顺序可能会导致这种关联性丢失。
所以,排序算法的 “非稳定”,主要指的是相同元素排序前后的相对顺序可能会改变。
冒泡排序在排序后不改变相同元素的相对位置,故是稳定排序算法;而选择排序,是非稳定排序算法。
要求稳定排序算法的案例#
确保相同元素的相对位置在排序前后一致的稳定排序算法在许多实际案例中都是必需的。以下是一些常见的需要保持相对位置的实际案例:
历史记录排序:在许多应用中,例如浏览器历史记录、聊天记录或编辑器中的操作记录,用户可能希望按照时间顺序查看记录,并且相同时间戳的记录应按其出现顺序显示。
优先级队列:在任务调度系统中,例如操作系统的进程调度或线程池中的任务调度,可能存在具有相同优先级的多个任务。为了公平地处理这些任务,稳定排序可以确保任务按照它们被添加到队列的顺序进行调度。
排名计算:在竞赛、比赛或投票等情境中,如果有多个参与者得分相同,则根据其出现的顺序确定名次是公平和合理的做法。稳定排序算法可以确保参与者的相对顺序不会变化,从而保持正确的排名结果。
特征提取:在机器学习和数据分析中,特征提取是一项重要任务。当对数据进行特征提取时,如果存在相同特征值的数据点,稳定排序可以确保相同特征值的数据点在输出中保持原有的相对位置。
交易处理:在金融领域中,当处理交易记录时,可能会遇到相同时间戳或相同价格的交易。为了确保交易的正确处理和顺序,稳定排序可以保持交易记录的相对顺序不变。