排序算法的python实现(以及相关题目)(待更新)

1. 九种排序算法实现

相关原理请点击此链接.

1 冒泡排序(Bubble Sort)

  1. 注意事项:
    1. 冒泡排序的平均时间复杂度为O(n**2)
    2. 对于一般情况,这种方法是排序时间效率最低的一种方法
    3. 是一种稳定排序法(元素交换是在相邻元素间进行,不会改变值相同元素的相对位置)
  2. 代码实现
def bubbleSort(arr):
	for i in range(len(arr)):
		for j in range(len(arr) - i - 1):
			if arr[j] > arr[j + 1]:
				arr[i], arr[j + 1] = arr[j + 1], arr[j]
	
	return arr

2 选择排序(Selection Sort)

  1. 注意事项:

    1. 选择排序的时间复杂度为O(n**2)
    2. 是一种不稳定排序(由于交换方式的不同可能会改变值相同元素的相对位置)
  2. 代码实现

def selectionSort(arr):
	for i in range(len(arr) - 1):
		# 记录一下最小数的索引
		min_i = i
		for j in range(i+1, len(arr)):
			if arr[j] < arr[min_i]:
				min_i = j
		# 将找到的最小数放在未排序的索引起始位置
		if i != min_i:
			arr[i], arr[min_i] = arr[min_i], arr[i]
	
	return arr

3. 插入排序(Insertion Sort)

  1. 注意:
    1. 插入排序的时间复杂度为O(n**2)
    2. 是一种稳定排序法
  2. 代码实现:
def insertionSort(arr):
	for i in range(1, len(arr)):
		temp = arr[i]
		j = i
		while j > 0 and arr[j - 1] > temp:
			arr[j] = arr[j - 1]
			j -= 1
		arr[j] = temp
	return arr

4. 希尔排序(Shell Sort)

  1. 注意:

    1. 按照若干间隔进行取值划分子序列,对每个子序列进行插入排序。逐渐缩小间隔的大小从而完成排序
    2. 排序的总趟数为logn
    3. 时间复杂度在O(nlogn)和O(n**2)之间
    4. 是一种不稳定排序法
  2. 代码实现:

def shellSort(arr):
	size = len(arr)
	gap = size//2

	while gap > 0:
		for i in range(gap, size):
			temp = arr[i]
			j = i
			while j >= gap and arr[j - gap] > temp:
				arr[j] = arr[j - gap]
				j-= gap
			arr[j] = temp
		gap = gap // 2
	return arr

5. 归并排序(Merge Sort)

  1. 注意:
    1. 采用递归将序列分成两半,然后两两排序合并,最终合并为结果
    2. 时间复杂度为O(nlogn)
    3. 是一种稳定排序算法
  2. 代码实现:
def merge(left_arr, right_arr):
	arr = []
	while left_arr and right_arr:
		if left_arr[0] <= right_arr[0]:
			arr.append(left_arr.pop(0))
		else:
			arr.append(right_arr.pop(0))
	while left_arr:
		arr.append(left_arr.pop(0))
	while right_arr:
		arr.append(right_arr.pop(0))
	return arr

def mergeSort(arr):
	size = len(arr)
	if size < 2:
		return arr
	mid = size // 2
	left_arr, right_arr = arr[:mid], arr[mid:]
	return merge(mergeSort(left_arr), mergeSort(right_arr))

6. 快速排序(Quick Sort)

  1. 注意:
    1. 思想:通过一趟排序将无序序列分为两个独立的序列。第一个序列的值均比第二个序列的值小。然后递归的排序两个子序列,以达到最终的有序序列
    2. 选择使用生成随机数来决定中值的取值。
    3. 时间复杂度为O(nlogn), 空间复杂度为O(n)
    4. 是一种不稳定排序法
  2. 代码实现
import random

def randomPartition(arr: [int], low: int, high:int):
	i = random.randint(low, high)
	arr[i], arr[high] = arr[high], arr[i]
	return partition(arr, low, high)

def partition(arr: int, low:int, high:int):
	x = arr[high]
	i = low - 1
	for j in range(low, high):
		if arr[j] <= arr[high]:
			i += 1
			arr[i], arr[j] = arr[j], arr[i]
	arr[i + 1], arr[high] = arr[high], arr[i + 1]
	return i + 1

def quickSort(arr, low, high):
	# low和high为数组的起始下标和终止下标
	if low < high:
		pi = randomPartition(arr, low, high)
		quickSort(arr, low, pi - 1)
		quickSort(arr, pi + 1, high)

7. 堆排序(Heap Sort)

  1. 注意:
    1. 思想:将数组转换为大顶堆,重复从大顶堆中取出数值最大的节点,并让剩余的堆维持大顶堆性质
    2. 定义:
      1. 大顶堆:根节点值>=子节点值
      2. 小顶堆:根节点值<=子节点值
    3. 包含内容:
      1. 初始堆建立方法
      2. 堆调整方法
      3. 堆排序方法
    4. 时间复杂度为O(nlogn), 空间复杂度为O(1)
    5. 调整的方式为自上向下的调整
    6. 是一种不稳定排序法
  2. 代码实现
# 1.调整为大顶堆
def heapify(arr:[int], index:int, end:int):
	left = index * 2 + 1
	right = left + 1
	while left <= end:
		# 当前节点为非叶子节点
		max_index = index
		if arr[left] > arr[max_index]:
			max_index = left
		if right <= end and arr[right] > arr[max_index]:
			max_index = right
		if max_index == index:
			# 如果不用交换,则证明交换已经结束
			break
		arr[index], arr[max_index] = arr[max_index], arr[index]
		# 继续调整子树
		index = max_index
		left = index * 2 + 1
		right = left + 1 
# 2. 初始化大顶堆
def buildMaxHeap(arr:[int]):
	size = len(arr)
	# (size - 2) // 2 是最后一个非叶节点,叶节点不用调整
	# 原因:叶子节点没有左右子树
	for i in range((size - 2) // 2, -1, -1):
		heapify(arr, i, size - 1)
	return arr

def maxHeapSort(arr: [int]):
	buildMaxHeap(arr)
	size = len(arr)
	for i in range(size):
		arr[0], arr[size-i-1] = arr[size-i-1], arr[0]
		heapify(arr, 0, size - i - 2)
	return arr

8. 计数排序(Counting Sort)

  1. 注意:
    1. 思想:使用一个额外的数组,其中第i个元素counts[i]是待排序数组arr中值等于i的元素个数。然后根据数组counts来将arr中的元素拍到正确的位置
    2. 当输入元素为n个0~k之间的整数时,时间复杂度为O(n + k)
    3. 一般用于排序整数,不适合于按字母顺序排序人名
    4. 数据范围很大时,需要大量时间和空间
    5. 一种稳定排序算法
  2. 代码实现
def countingSort(arr):
	arr_min, arr_max = min(arr), max(arr)
	size = arr_max - arr_min + 1
	counts = [0 for _ in range(size)]

	for num in arr:
		counts[num - arr_min] += 1
	for j in range(1, size):
	# 统计每个元素排序后所对应的索引
		counts[j] += counts[j - 1]
	
	res = [0 for _ in range(len(arr))]
	for i in range(len(arr) -1, -1, -1):
		res[counts[arr[i] - arr_min] - 1] = arr[i]
		counts[arr[i] - arr_min] -= 1
	
	return res

9. 桶排序(Bucket Sort)

  1. 注意:
    1. 思想:将未排序的数组分到若干个桶中,每个桶的元素再进行单独排序
    2. 划分为长度相等的若干个桶
    3. 可以在线性时间内完成,当元素个数为n, 桶个数为m时,时间复杂度为O(n+m), 空间复杂度为O(n+m)
    4. 根据桶内元素的排序算法来确定桶排序是否为稳定排序算法
  2. 代码实现:
def insertionSort(arr):
	for i in range(1, len(arr)):
		temp = arr[i]
		j = i
		while j > 0 and arr[j] > temp:
			arr[j] = arr[j - 1]
			j -= 1
		arr[j] = temp
	return arr

def bucketSort(arr, bucket_size = 5):
	arr_min, arr_max = min(arr), max(arr)
	bucket_count = (arr_max - arr_min) / bucket_size + 1
	buckets = [[] for _ in range(bucket_count)]

	for num in arr:
		buckets[(num - arr_min) //bucket_size].append(num)
	
	res = []
	for bucket in buckets:
		insertionSort(bucket)
		res.extend(bucket)
	return res

9. 基数排序(Radix Sort)

  1. 注意:
    1. 思想:将整数按位数切割成不同的数字,然后按每个位数比较进行排序
    2. 分为最低为优先法和最高位优先法
    3. 时间复杂度为O(k*n), 空间复杂度为O(k + n)
  2. 代码实现:
def radixSort(arr):
	size = len(str(max(arr)))

	for i in range(size):
		buckets = [[] for _ in range(10)]
		for num in arr:
			buckets[num//(10**i)%10].append(num)
		arr.clear()
		for bucket in buckets:
			for num in bucket:
				arr.append(num)

	return arr

2. 相关题目:

剑指offer45.把数组排成最小的数.

思路: 刚开始思考到了使用字符串的比较来进行排序,不过只想到了长度为一的字符串大小比较那一层,没有更加深入的去思考。
在这个题中,对于任何字符串,只要a+b>b+a, 那么就有a>b, 这就是一个大小比较的策略,之后就按照一般的排序算法对其排序,最后拼接字符串即可

  1. 冒泡排序
class Solution:
    def minNumber(self, nums: List[int]) -> str:
        n = len(nums)
        for i in range(n):
            nums[i] = str(nums[i])
        
        for i in range(n):
            for j in range(n - i - 1):
                if nums[j] + nums[j + 1] > nums[j + 1] + nums[j]:
                    nums[j], nums[j + 1] = nums[j + 1], nums[j]
        return ''.join(nums)
1. 时间复杂度:O(n**2)
2. 空间复杂度:
  1. 选择排序
class Solution:
    def minNumber(self, nums: List[int]) -> str:
        n = len(nums)
        for i in range(n):
            nums[i] = str(nums[i])
        
        for i in range(n - 1):
            min_i = i
            for j in range(i + 1, n):
                if nums[min_i] + nums[j] > nums[j] + nums[min_i]:
                    min_i = j
            if i != min_i:
                nums[min_i], nums[i] = nums[i], nums[min_i] 
        return ''.join(nums)
  1. 插入排序

283.移动零.

思路:原本考虑的是排序算法,可是想到稳定排序算法只是不改变值相同元素间的相对位置,不符合题意。最后想到利用双指针算法来进行求解
当右指针碰到非零元素时,交换左右指针对应元素,使得左指针和右指针之间的元素为0且不改变元素的相对位置

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        left = 0
        right = 0
        n = len(nums)
        while right < n:
            if nums[right] != 0:
                nums[left], nums[right] = nums[right], nums[left]
                left += 1
            right += 1

912.排序数组.

思路:就是一般的排序算法,不过注意,时间复杂度为O(n**2)的排序算法在这个题目下会超时,只能从时间复杂度较低的排序算法中找。
如快速排序、堆排序、归并排序等

506.相对名次

思路:整体上是一个排序算法,将排完序后的下标映射到原数组中即可

  1. 直接利用sort(像是作弊,只是验证一下思路是否可行)
class Solution:
    def findRelativeRanks(self, score: List[int]) -> List[str]:
        ls = []
        ls[:] = score
        n = len(score)
        ls.sort(reverse = True)
        for i in range(n):
            if ls.index(score[i]) == 0:
                score[i] = 'Gold Medal'
            elif ls.index(score[i]) == 1:
                score[i] = 'Silver Medal'
            elif ls.index(score[i]) == 2:
                score[i] = 'Bronze Medal'
            else:
                score[i] = str(ls.index(score[i])+1)
        return score
  1. 尝试使用归并排序
def merge(left_arr, right_arr):
    arr = []
    while left_arr and right_arr:
        if left_arr[0] >= right_arr[0]:
            arr.append(left_arr.pop(0))
        else:
            arr.append(right_arr.pop(0))
    while left_arr:
        arr.append(left_arr.pop(0))
    while right_arr:
        arr.append(right_arr.pop(0))
    return arr
def mergeSort(arr):
    size = len(arr)
    if size < 2:
        return arr
    mid = size//2
    left_arr, right_arr = arr[:mid], arr[mid:]
    return merge(mergeSort(left_arr), mergeSort(right_arr))
class Solution:
    def findRelativeRanks(self, score: List[int]) -> List[str]:
        ls = []
        ls[:] = score
        n = len(score)
        ls = mergeSort(ls)
        for i in range(n):
            if ls.index(score[i]) == 0:
                score[i] = 'Gold Medal'
            elif ls.index(score[i]) == 1:
                score[i] = 'Silver Medal'
            elif ls.index(score[i]) == 2:
                score[i] = 'Bronze Medal'
            else:
                score[i] = str(ls.index(score[i])+1)
        return score
  1. 尝试使用希尔排序
def shellSort(arr):
    size = len(arr)
    gap = size // 2

    while gap > 0 :
        for i in range(gap, size):
            temp = arr[i]
            j = i
            while j >= gap and arr[j - gap] < temp:
                arr[j] = arr[j - gap]
                j -= gap
            arr[j] = temp
        gap = gap // 2
    return arr

class Solution:
    def findRelativeRanks(self, score: List[int]) -> List[str]:
        ls = []
        ls[:] = score
        n = len(score)
        ls = shellSort(ls)
        for i in range(n):
            if ls.index(score[i]) == 0:
                score[i] = 'Gold Medal'
            elif ls.index(score[i]) == 1:
                score[i] = 'Silver Medal'
            elif ls.index(score[i]) == 2:
                score[i] = 'Bronze Medal'
            else:
                score[i] = str(ls.index(score[i])+1)
        return score

75.颜色分类

  1. 思路:本质上就是一个排序算法,将数组中的元素按照升序的方式排列。
  2. 具体代码:
    1. 直接使用sort验证思路(思路正确,就不写代码了,这是一种作弊哈哈)
    2. 堆排序(时间复杂度为O(1)):
    def heapify(arr, index, end):
        left = 2 * index + 1
        right = left + 1
        max_index = index
        while left <= end:
            if arr[left] > arr[max_index]:
                max_index = left
            if right <= end and arr[right] > arr[max_index]:
                max_index = right
            if max_index == index:
                break
            arr[index], arr[max_index] = arr[max_index], arr[index]
            index = max_index
            left = 2 * index + 1
            right = left + 1
    
    def buildMaxHeap(arr):
        size = len(arr)
        for i in range((size - 2) // 2, -1, -1):
            heapify(arr, i, size - 1)
        return arr
    class Solution:
        def sortColors(self, nums: List[int]) -> None:
            buildMaxHeap(nums)
            size = len(nums)
            for i in range(size):
                nums[0], nums[size - i - 1] = nums[size - i - 1], nums[0]
                heapify(nums, 0, size - i - 2)
    
    
    1. 对0,1,2计数,并重写数组(荷兰国旗问题)
    class Solution:
        def sortColors(self, nums: List[int]) -> None:
            ls = [0, 0, 0]
            for i in nums:
                ls[i] += 1
            mid = []
            for i in range(3):
                if ls[i] != 0:
                    for j in range(ls[i]):
                        mid.append(i)
            nums[:] = mid
    
    1. 单指针
    class Solution:
    def sortColors(self, nums: List[int]) -> None:
        ptr = 0
        n = len(nums)
        for i in range(n):
            if nums[i] == 0:
                nums[ptr], nums[i] = nums[i], nums[ptr]
                ptr += 1
        for i in range(n):
            if nums[i] == 1:
                nums[ptr], nums[i] = nums[i], nums[ptr]
                ptr += 1
    

215.数组中的第K大元素

  1. 思路:将数组进行排序,输出第k个(或者倒数第k个元素即可)
  2. 代码实现:
    1. 最大堆
    def heapify(arr, index, end):
        left = 2 * index + 1
        right = left + 1
        while left <= end:
            max_index = index
            if arr[left] > arr[max_index]:
                max_index = left
            if right <= end and arr[right] > arr[max_index]:
                max_index = right
            if max_index == index:
                break
            arr[index], arr[max_index] = arr[max_index], arr[index]
            index = max_index
            left = 2 * index + 1
            right = left + 1
    
    def buildMaxHeap(arr):
        size = len(arr)
        for i in range((size - 2) // 2, -1, -1):
            heapify(arr, i, size - 1)
        return arr
    class Solution:
        def findKthLargest(self, nums: List[int], k: int) -> int:
            buildMaxHeap(nums)
            size = len(nums)
            for i in range(size):
                nums[0], nums[size - i - 1] = nums[size - i - 1], nums[0]
                heapify(nums, 0, size - i - 2)
            return nums[-k]
    
    1. 最大堆的改进算法:我们只需要找出第k次选择删除的最大值即为最终答案, 不需要我们对其进行完整的排序,所以,我们可以在中途直接跳出循环
    def heapify(arr, index, end):
        left = 2 * index + 1
        right = left + 1
        while left <= end:
            max_index = index
            if arr[left] > arr[max_index]:
                max_index = left
            if right <= end and arr[right] > arr[max_index]:
                max_index = right
            if max_index == index:
                break
            arr[index], arr[max_index] = arr[max_index], arr[index]
            index = max_index
            left = 2 * index + 1
            right = left + 1
    
    def buildMaxHeap(arr):
        size = len(arr)
        for i in range((size - 2) // 2, -1, -1):
            heapify(arr, i, size - 1)
        return arr
    class Solution:
        def findKthLargest(self, nums: List[int], k: int) -> int:
            buildMaxHeap(nums)
            size = len(nums)
            count = 0
            for i in range(size):
                nums[0], nums[size - i - 1] = nums[size - i - 1], nums[0]
                count += 1
                if count == k:
                    return nums[size - i - 1]
                heapify(nums, 0, size - i - 2)
                
    

1122.数组的相对排序

  1. 思路:由于给定了数组中的值在0和1000之间,所以可以尝试一下使用计数排序的方法来解决该问题
  2. 代码实现:
    1. 计数排序:
    class Solution:
        def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
            arr = [0 for i in range(1001)]
            for i in range(len(arr1)):
                arr[arr1[i]] += 1
            ans = []
            for i in range(len(arr2)):
                while arr[arr2[i]] > 0:
                    ans.append(arr2[i])
                    arr[arr2[i]] -= 1
            for i in range(1001):
                while arr[i] > 0:
                    ans.append(i)
                    arr[i] -= 1
            return ans
    

908.最小差值

  1. 思路:直接找打原数组的最大值和最小值,做差与2 * k比较,如果大于2k,返回与2k的差值,如果小于2*k, 返回0
  2. 代码实现:
class Solution:
    def smallestRangeI(self, nums: List[int], k: int) -> int:
        num_min = min(nums)
        num_max = max(nums)
        ans = num_max - num_min
        if ans > 2 * k:
            return ans - 2 * k
        else:
            return 0
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值