程序员必须掌握的十大排序算法「上」

1. 排序算法的重要性

排序算法是指将一组无序数据按照一定的规则进行排列的过程,对于程序员来说,排列数据使得程序运行的更快,增加程序的执行效率,提高程序的质量,是非常重要的。因此,掌握排序算法是程序员必不可少的技能之一。

2. 排序的分类

2.1 按照数据结构划分

排序算法可以根据不同的数据结构进行分类,主要包括:

数组排序:对于一维、二维或多维数组进行排序。

链表排序:对于链表结构中的节点进行排序。

树形结构排序:对于二叉树、AVL树、堆排序树、B树、红黑树进行排序。

2.2 按照排序方式划分

排序算法还可以按照排序的方式进行分类,包括:

比较排序:通过比较关键字大小来进行排序,包括插入排序、希尔排序、归并排序、快速排序、堆排序、冒泡排序、选择排序等。

非比较排序:不通过比较关键字大小来进行排序,包括桶排序、计数排序、基数排序等。

3. 十大排序算法

下面介绍程序员必须掌握的十大排序算法:

3.1 冒泡排序

冒泡排序是一种简单的排序算法,它的原理是通过不断交换相邻元素的位置,将大的元素逐渐的往后移。

def bubble_sort(nums):

n = len(nums)

for i in range(n):

for j in range(n-i-1):

if nums[j] > nums[j+1]:

nums[j], nums[j+1] = nums[j+1], nums[j]

return nums

冒泡排序的时间复杂度是O(n2)。

3.2 选择排序

选择排序是一种简单的排序算法,它的原理是指定一个最小值,从数组中查找最小值并将其交换到数组的最前面。

def selection_sort(nums):

n = len(nums)

for i in range(n):

min_index = i

for j in range(i, n):

if nums[j] < nums[min_index]:

min_index = j

nums[i], nums[min_index] = nums[min_index], nums[i]

return nums

选择排序的时间复杂度是O(n2)。

3.3 插入排序

插入排序是一种简单的排序算法,它的原理是从数组的第二个元素开始,将当前元素插入到已排序好的数组中,保持已排序数组的有序性。

def insertion_sort(nums):

n = len(nums)

for i in range(1, n):

key = nums[i]

j = i - 1

while j >= 0 and nums[j] > key:

nums[j+1] = nums[j]

j -= 1

nums[j+1] = key

return nums

插入排序的时间复杂度是O(n2)。

3.4 希尔排序

希尔排序是一种基于插入排序的快速、高效的排序算法,它的原理是将数组进行分组,然后对每组中的元素进行插入排序。

def shell_sort(nums):

n = len(nums)

gap = n // 2

while gap > 0:

for i in range(gap, n):

temp = nums[i]

j = i

while j >= gap and nums[j-gap] > temp:

nums[j] = nums[j-gap]

j -= gap

nums[j] = temp

gap = gap // 2

return nums

希尔排序的时间复杂度的比较复杂,最好情况下是O(n),最坏情况下是O(n2)。

3.5 快速排序

快速排序是一种基于分治思想的排序算法,它的原理是指定一个基准元素,通过分区的方式,将数组分为两个子数组,然后分别对左右两边的子数组进行递归排序。

def quick_sort(nums):

if len(nums) <= 1:

return nums

pivot = nums[len(nums)//2] #选择基准值

left, right, mid = [], [], []

for num in nums:

if num < pivot:

left.append(num)

elif num > pivot:

right.append(num)

else:

mid.append(num)

return quick_sort(left) + mid + quick_sort(right)

快速排序的时间复杂度最好情况下是O(nlogn),最坏情况下是O(n2)。

3.6 归并排序

归并排序是一种基于分治思想的排序算法,它的原理是将数组分为两个子数组,然后递归地对两个子数组进行排序,并最终将两个排序好的子数组合并成一个有序数组。

def merge_sort(nums):

if len(nums) <= 1:

return nums

mid = len(nums)//2 #获取中间值

left, right = nums[:mid], nums[mid:]

return merge(merge_sort(left), merge_sort(right))

def merge(left, right):

result = []

i, j = 0, 0

while i < len(left) and j < len(right):

if left[i] < right[j]:

result.append(left[i])

i += 1

else:

result.append(right[j])

j += 1

result += left[i:]

result += right[j:]

return result

归并排序的时间复杂度是O(nlogn)。

3.7 堆排序

堆排序是一种基于堆的排序算法,它的原理是将无序数组构建成一个二叉堆,并递归地将最大值移动到数组的末尾。

def heap_sort(nums):

n = len(nums)

for i in range(n//2 - 1, -1, -1):

heapify(nums, n, i)

for i in range(n-1, 0, -1):

nums[i], nums[0] = nums[0], nums[i]

heapify(nums, i, 0)

return nums

def heapify(nums, n, i):

largest = i

l = 2*i + 1

r = 2*i + 2

if l < n and nums[l] > nums[largest]:

largest = l

if r < n and nums[r] > nums[largest]:

largest = r

if largest != i:

nums[i], nums[largest] = nums[largest], nums[i]

heapify(nums, n, largest)

堆排序的时间复杂度是O(nlogn)。

3.8 计数排序

计数排序是一种比较简单的排序算法,它的原理是统计数组中每个元素出现的次数,并根据元素出现的次数将元素放入有序数组中。

def counting_sort(nums):

n = len(nums)

output, count = [0] * n, [0] * (max(nums)+1)

for num in nums:

count[num] += 1

for i in range(1, len(count)):

count[i] += count[i-1]

for i in range(n-1, -1, -1):

output[count[nums[i]]-1] = nums[i]

count[nums[i]] -= 1

return output

计数排序的时间复杂度是O(n+k),其中k是数组中最大元素的个数。

3.9 桶排序

桶排序是一种基于计数排序的排序算法,它的原理是将数组分成若干个桶,对桶内的元素进行排序,并按顺序将所有桶的元素排成一个有序数组。

def bucket_sort(nums):

n, k = len(nums), max(nums)

gap = (k+1) // n

buckets = [[] for _ in range(n)]

for num in nums:

i = min(num // gap, n-1)

buckets[i].append(num)

if len(buckets[i]) > 1:

j = len(buckets[i]) - 2

while j >= 0 and buckets[i][j] > num:

buckets[i][j+1] = buckets[i][j]

j -= 1

buckets[i][j+1] = num

return [num for bucket in buckets for num in bucket]

桶排序的时间复杂度是O(n+k),其中k是算法中桶的个数。

3.10 基数排序

基数排序是一种基于分治思想的排序算法,它的原理是首先按照个位数进行排序,然后按照十位、百位等高位进行排序。

def radix_sort(nums):

radix = 10

max_num = max(nums)

exp = 1

while max_num // exp > 0:

buckets = [[] for _ in range(radix)]

for num in nums:

buckets[num//exp % radix].append(num)

nums = [num for bucket in buckets for num in bucket]

exp *= 10

return nums

基数排序的时间复杂度是O(d(n+k)),其中d是数字位数,k是基数。

4. 总结

本文介绍了程序员必须掌握的十大排序算法,这些算法包括冒泡排序、选择排序、插入排序、希尔排序、快速排序、归并排序、堆排序、计数排序、桶排序、基数排序,对于程序员来说,排列数据使得程序运行的更快,增加程序的执行效率,提高程序的质量,是非常重要的,掌握排序算法是程序员必不可少的技能之一。

后端开发标签