1. 排序算法介绍
排序算法是计算机科学中一种用来将一串数据按照特定顺序进行排列的算法。常见的排序算法有冒泡排序、插入排序、选择排序、快速排序、归并排序等。其中,冒泡排序、插入排序和选择排序被称为经典排序算法。
2. 冒泡排序
冒泡排序的基本思想是:重复扫描要排序的数列,每次比较相邻两个数的大小,如果前一个数比后一个数大,则交换这两个数的位置,直到整个数列都有序为止。冒泡排序属于稳定排序,时间复杂度为O(n^2)。
下面是python实现冒泡排序的示例代码:
def bubble_sort(arr):
for i in range(len(arr)):
for j in range(1, len(arr) - i):
if arr[j - 1] > arr[j]:
arr[j - 1], arr[j] = arr[j], arr[j - 1]
return arr
代码解释:
首先定义了一个函数bubble_sort,该函数接收一个列表arr作为参数。
然后使用两层循环,外层循环控制需要比较的轮数,内层循环表示每一轮需要比较的数的下标范围。
如果相邻两个数的大小关系不符合要求,则进行交换。
最后返回排好序的列表。
2.1 冒泡排序的优化
冒泡排序的时间复杂度较高,因此可以对其进行一些优化。
2.1.1 设置flag
我们可以记录每一轮比较中是否发生了交换,如果没有交换,则说明整个数列已经有序,可以提前结束循环。
下面是优化后的代码:
def bubble_sort_v1(arr):
for i in range(len(arr)):
flag = True # 设置标志位,记录是否发生交换
for j in range(1, len(arr) - i):
if arr[j - 1] > arr[j]:
arr[j - 1], arr[j] = arr[j], arr[j - 1]
flag = False # 标志位置为False
if flag: # 如果没有发生交换,说明已经有序
break
return arr
代码解释:
同样是定义了一个函数bubble_sort_v1,该函数接收一个列表arr作为参数。
在外层循环之前,先设置一个标志位flag,初始化为True。
在内层循环中,如果发生了交换,则将标志位设置为False。
内层循环结束后,判断标志位是否为True,若为True,则说明整个数列已经有序,可以提前结束循环。
最后返回排好序的列表。
2.1.2 双向冒泡排序
冒泡排序默认是从左到右依次比较相邻两个数的大小,可以通过双向冒泡排序进行优化。双向冒泡排序是指同时从左右两个方向进行比较和交换,可以大大降低排序时间。
下面是双向冒泡排序的示例代码:
def bubble_sort_v2(arr):
left, right = 0, len(arr) - 1 # 定义左右边界
while left < right:
flag = True # 设置标志位,记录是否发生交换
for i in range(left, right):
if arr[i] > arr[i + 1]:
arr[i], arr[i + 1] = arr[i + 1], arr[i]
flag = False # 标志位置为False
right -= 1 # 右边界左移一位
for j in range(right, left, -1):
if arr[j - 1] > arr[j]:
arr[j - 1], arr[j] = arr[j], arr[j - 1]
flag = False # 标志位置为False
left += 1 # 左边界右移一位
if flag: # 如果没有发生交换,说明已经有序
break
return arr
代码解释:
同样是定义了一个函数bubble_sort_v2,该函数接收一个列表arr作为参数。
在外层使用while循环,并定义左右边界left和right,初始值分别为0和len(arr)-1。
内层循环分别从左往右和从右往左遍历,并进行比较和交换操作。
内层循环结束后更新左右边界,并判断是否有序或发生了交换。
最后返回排好序的列表。
3. 插入排序
插入排序的基本思想是:将待排序的序列分成两部分,有序部分和无序部分,每次从无序部分取出一个数,插入到有序部分的适当位置,直到整个序列有序为止。插入排序属于稳定排序,时间复杂度为O(n^2)。
下面是python实现插入排序的示例代码:
def insertion_sort(arr):
for i in range(1, len(arr)):
for j in range(i, 0, -1):
if arr[j] < arr[j - 1]:
arr[j], arr[j - 1] = arr[j - 1], arr[j]
else:
break
return arr
代码解释:
同样是定义了一个函数insertion_sort,该函数接收一个列表arr作为参数。
外层循环表示需要插入的数的下标范围,初始值为1到len(arr)。
内层循环表示在有序部分中找到合适的位置,并插入待排序的数。
如果有序部分的最后一个数比待排序的数大,则将其后移一位,直到找到合适的位置。
最后返回排好序的列表。
3.1 插入排序的优化
插入排序的时间复杂度较高,因此可以对其进行一些优化。
3.1.1 二分查找优化
对于已经排好序的列表,可以使用二分查找的方式来确定待插入数的位置,减少比较次数,从而提高效率。
下面是使用二分查找优化后的插入排序代码:
def binary_insertion_sort(arr):
for i in range(1, len(arr)):
left, right = 0, i - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] > arr[i]:
right = mid - 1
else:
left = mid + 1
for j in range(i - 1, left - 1, -1):
arr[j + 1], arr[j] = arr[j], arr[j + 1]
return arr
代码解释:
同样是定义了一个函数binary_insertion_sort,该函数接收一个列表arr作为参数。
外层循环表示需要插入的数的下标范围,初始值为1到len(arr)。
使用二分查找的方式确定待插入数的位置。
在有序部分中,从待插入数的位置开始到有序部分的最后一个数,都向后移动一位,然后将待插入数插入到空出来的位置上。
最后返回排好序的列表。
4. 选择排序
选择排序的基本思想是:将待排序的序列分成两部分,有序部分和无序部分,每次从无序部分中选出一个最小的数,插入到有序部分的末尾,直到整个序列有序为止。选择排序不稳定,时间复杂度为O(n^2)。
下面是python实现选择排序的示例代码:
def selection_sort(arr):
for i in range(len(arr)):
min_index = i
for j in range(i + 1, len(arr)):
if arr[j] < arr[min_index]:
min_index = j
arr[i], arr[min_index] = arr[min_index], arr[i]
return arr
代码解释:
同样是定义了一个函数selection_sort,该函数接收一个列表arr作为参数。
外层循环表示需要寻找最小值的下标范围,初始值为0到len(arr)-1。
内层循环表示在无序部分中找到最小值的下标。
找到最小值后,将其与无序部分的第一个数进行交换,即插入到有序部分的末尾。
最后返回排好序的列表。
4.1 选择排序的优化
选择排序的时间复杂度较高,因此可以对其进行一些优化。
4.1.1 双向选择排序
选择排序默认是从左到右依次选择最小的数,可以通过双向选择排序进行优化。双向选择排序是指同时从左右两个方向选出最小的数,然后交换位置,可以大大降低排序时间。
下面是双向选择排序的示例代码:
def selection_sort_v1(arr):
left, right = 0, len(arr) - 1 # 定义左右边界
while left < right:
min_index, max_index = left, right # 定义最小值和最大值的下标
if arr[min_index] > arr[max_index]:
arr[min_index], arr[max_index] = arr[max_index], arr[min_index]
for i in range(left + 1, right):
if arr[i] < arr[min_index]:
min_index = i
elif arr[i] > arr[max_index]:
max_index = i
arr[left], arr[min_index] = arr[min_index], arr[left]
arr[right], arr[max_index] = arr[max_index], arr[right]
left += 1 # 左边界右移一位
right -= 1 # 右边界左移一位
return arr
代码解释:
同样是定义了一个函数selection_sort_v1,该函数接收一个列表arr作为参数。
在外层使用while循环,并定义左右边界left和right,初始值分别为0和len(arr)-1。
在内层循环中,同时从左右两个方向选出最小的数和最大的数,并交换位置。
内层循环结束后更新左右边界。
最后返回排好序的列表。
4.1.2 堆排序
堆排序是一种利用堆这种数据结构进行排序的算法,它是不稳定的,时间复杂度为O(nlogn)。
堆排序的基本思想是:将待排序的数据按照某种方式构造成一个堆,然后每次取出堆顶的元素放到已排序序列的末尾,重复该操作直到整个序列有序为止。
下面是python实现堆排序的示例代码:
def heap_sort(arr):
def sift_down(start, end):
root = start
while True:
child = 2 * root + 1
if child > end:
break
if child + 1 <= end and arr[child] < arr[child + 1]:
child += 1
if arr[root] < arr[child]:
arr[root], arr[child] = arr[child], arr[root]
root = child
else:
break
# 构建大根堆
for i in range(len(arr) // 2 - 1, -1, -1):
sift_down(i, len(arr) - 1)
# 取出堆顶元素,放到已排序序列的末尾
for i in range(len(arr) - 1, 0, -1):
arr[0], arr[i] = arr[i], arr[0]
sift_down(0, i - 1)
return arr
代码解释:
先定义一个函数sift_down用于对指定区域的数据进行下沉排序。
在构建大根堆之前,先找到最后一个非叶子节点,并从后往前依次进行下沉排序得到大根堆。
再从堆顶依次取出元素放到已排序序列的末尾,重复该操作直到整个序列有序为止。
最后返回排好序的列表。
5. 总结
在排序算法中,不同的算法有不同的优缺点,根据具体的应用场景来选择适合的算法。在实际开发中,可以根据数据量的大小和特征进行选择。
本文介绍了冒泡排序、插入排序、选择排序和堆排序四种经典排序算法的实现方法,其中冒泡排序、插入排序和选择排序属于初级排序算法,时间复杂度较高,可以通过优化手段来提高效率,而堆排序是高级排序算法,时间复杂度较低,但实现起来较为复杂。
以上算法的基本思想和示例代码只是为了演示排序算法的实现过程,实际开发中的算法实现可能会有所不同,希望读者能够理解算法的思想和主要步骤。