python实现选择排序

本文介绍了Python实现的选择排序、堆排序两种算法,详细讲解了它们的基本思想、时间空间复杂度,并提供了具体的代码实现。选择排序的时间效率为O(n²),而堆排序的时间效率为O(nlog2N),两者都是不稳定的排序算法。堆排序通过构建大根堆或小根堆进行排序,选择排序则是通过每趟选择最小或最大元素与已排序部分交换来完成排序。
摘要由CSDN通过智能技术生成

排序算法:
python实现基数排序
python实现归并排序
python实现交换排序
python实现选择排序
python实现插入排序
python实现桶排序

简单选择排序
基本思想:假设排序表为L[1…n],第i趟排序即从L[i…n]中选择关键字最小的的元素与L[i]交换,每一趟排序可以确定一个元素的最终位置,则经过n-1趟排序可以使得整个排序表有序。
在这里插入图片描述

def SelectionSort(A):
    le=len(A)
    for i in range(le):#遍历次数
        for j in range(i+1,le):#查找待排序序列中的最小元素并交换
            if A[i]>A[j]:
                A[i],A[j]=A[j],A[i]
    print(A)
tes=[2,4,5,46,34,56,345,34,454]
SelectionSort(tes)#[2, 4, 5, 34, 34, 46, 56, 345, 454]

空间效率:仅使用常数个辅助单元,因此空间效率为O(1)
时间效率:O(n²)
它是一个不稳定的排序算法。

堆排序
堆排序是一种树形选择排序方法,在排序过程中,将L[1…n]看作一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系,在当前无序区中选择关键字最大(或最小)的元素。
堆的定义:
n个关键字序列L[1…n]称为堆,当且仅当该序列满足:
1)L[i]<=L[2i]且L[i]<=L[2i+1](小根堆)
2) L[i]>=L[2i]且L[i]>=L[2i+1](大根堆)
在这里插入图片描述
堆排序的关键是构造初始堆,对初始序列建堆,就是一个反复筛选的过程。n个结点的完全二叉树,最后一个结点是n//2个节点的孩子。对n//2个节点为根的子树筛选(对于大根堆,若根结点的关键字小鱼左右子女中关键字较大者,则交换),使该子树成为堆。之后向前依次对各节点(n//2~1)为根的子树进行筛选,看该结点是否大于其左右子节点的值,若不是,则将左右子结点中较大值与之交换,交换后可能会破坏下一级的堆,于是继续采用上述方法构造下一级的堆,直到以该结点为根的子树构成堆为止。
在这里插入图片描述

同时,堆也支持删除和插入操作。由于堆顶元素为最大值或者最小值,删除堆顶元素时,先将堆的最后一个元素与堆顶元素交换,由于此时堆得性质被破坏,需对此时的根结点进行向下调整操作。
对堆进行插入操作时,先将新结点放在堆的末端,再对这个结点执行向上调整操作。

在这里插入图片描述在这里插入图片描述

大根堆排序(Heap Sort)

一种基于堆的排序算法,它利用了堆数据结构的特性来实现排序。大根堆是一种满足堆属性的完全二叉树,即每个节点的值都大于等于其子节点的值。
算法逻辑:
1.构建大根堆:将待排序数组看作是一个完全二叉树,从最后一个非叶子节点开始,依次向上调整使得每个子树都满足大根堆的性质。这个过程称为“堆化(Heapify)”。
2.调整大根堆:重复进行以下操作,直到所有节点都满足大根堆的性质:
3.将根节点与最后一个节点交换位置,即将最大值移到数组末尾。
4.缩小堆的范围(即排除最后一个节点),并对根节点进行一次“下沉”操作,使得根节点重新满足大根堆的性质。
堆排序:通过不断地进行步骤2,直到堆的大小减小到1,最终得到一个有序的数组。

# 实现一个最大堆
class MaxHeap(object):
    """
    实现一个大顶堆
    """

    def __init__(self):
        self.array = [] # 用一个数组存放堆中元素

    def heapify(self, array):
        """
        对传入的数组进行堆化
        """
        for a in array:
            self.push(a)
        return self.array

    def get_size(self):
        """
        返回堆的大小
        """
        return len(self.array)

    def _parent(self, index):
        """
        返回某个节点的父节点
        """
        if index == 0:
            raise Exception('Index 0 has no parent')
        return int((index - 1) / 2)

    def _left_child(self, index):
        """
        返回左孩子节点的索引
        """
        return index * 2 + 1

    def _right_child(self, index):
        """
        返回右边孩子节点的索引
        """
        return index * 2 + 2

    def _shift_up(self, k):
        """
        节点上移动,将当前节点与其父亲节点比较大小,如果比父亲节点大,
        则交换其位置,重复只执行上述过程,直到当前节点比父亲节点小。
        """
        while k > 0 and self.array[self._parent(k)] < self.array[k]:
            # 交换节点与父节点的值
            self.array[self._parent(k)], self.array[k] = self.array[k], self.array[self._parent(k)]
            k = self._parent(k)

    def _shift_down(self, k):
        """
        节点下移动, 当前节点与它左右孩子中最大的节点交换位置
        """
        while self._left_child(k) < self.get_size():
            choose_index = self._left_child(k)  # 左孩子的索引
            # 先比较左右孩子的大小,选择较大的那个孩子再与父亲节点进行比较
            if choose_index + 1 < self.get_size() and self.array[choose_index + 1] > self.array[choose_index]:
                choose_index = self._right_child(k)
            if self.array[choose_index] <= self.array[k]:  # 如果最大的孩子比父亲节点小,退出循环
                break
            # 否则父亲节点和最大的子节点交换位置
            self.array[choose_index], self.array[k] = self.array[k], self.array[choose_index]
            k = choose_index  # 进行下次循环

    def push(self, value):
        """
        添加一个元素后,需要对堆重新进行堆化,具体过程就是对堆尾元素执行上移操作;
        """
        self.array.append(value)
        self._shift_up(self.get_size() - 1)  # 相当于对堆进行重新堆化

    def pop(self):
        """
        返回堆顶元素,将堆顶元素和堆最后一个元素交换,
        然后返回最后一个元素,最后对堆顶元素进行下沉操作(重新堆化)
        """
        ret = self.find_max()
        self.array[0], self.array[self.get_size() - 1] = self.array[self.get_size() - 1], self.array[0]
        self.array.pop(-1)  # 删除最后一个元素
        self._shift_down(0)
        return ret

    def find_max(self):
        """
        查看堆中的最大值
        """
        if self.array:
            return self.array[0]
        else:
            raise Exception('Empty heap has no value')

# 测试我们实现的大顶堆
test = [12, 11, 10, 9, 6, 7, 8, 13]
max_heap = MaxHeap()
print(max_heap.heapify(test)) # 对一个数组执行堆化
print(max_heap.pop()) # 弹出堆顶元素
print(max_heap.array) 
max_heap.push(14) # 推入一个元素
print(max_heap.array)

空间效率:仅使用常数个辅助单元,因此空间效率为O(1)
时间效率:O(nlog2 N)
它是一种不稳定的排序算法

小根堆排序算法(Min Heap Sort)

一种基于堆的排序算法,它通过构建小根堆(每个节点的值都小于或等于其子节点的值)来进行排序。其基本逻辑是:
1.将待排序的数组构建成一个小根堆。
2.不断从堆顶(即根节点)取出最小值,并将其与堆的最后一个元素交换,然后调整堆,使其保持小根堆的性质。
3.重复步骤2,直到堆中的元素全部取出,得到有序的数组。

def min_heapify(arr, n, i):
    smallest = i
    left_child = 2 * i + 1
    right_child = 2 * i + 2

    if left_child < n and arr[left_child] < arr[smallest]:
        smallest = left_child

    if right_child < n and arr[right_child] < arr[smallest]:
        smallest = right_child

    if smallest != i:
        arr[i], arr[smallest] = arr[smallest], arr[i]
        min_heapify(arr, n, smallest)

def build_min_heap(arr):
    n = len(arr)
    for i in range(n // 2 - 1, -1, -1):
        min_heapify(arr, n, i)

def heap_sort(arr):
    n = len(arr)
    build_min_heap(arr)
    for i in range(n - 1, 0, -1):
        arr[0], arr[i] = arr[i], arr[0]
        min_heapify(arr, i, 0)

# 测试
arr = [12, 11, 13, 5, 6, 7]
heap_sort(arr)
print("排序后的数组:", arr)

算法逻辑讲解:
min_heapify函数:用于维护小根堆的性质,假设数组中第i个元素的左子节点索引为2i+1,右子节点索引为2i+2。在min_heapify函数中,首先找到当前节点与其左右子节点中的最小值,并记录最小值的索引,然后将当前节点与最小值交换位置,接着递归调整以最小值为根节点的子树,使其满足小根堆的性质。
build_min_heap函数:用于构建初始的小根堆。从数组的中间位置开始,依次对每个非叶子节点调用min_heapify函数,使得整个数组构成一个小根堆。
heap_sort函数:排序的核心逻辑,首先构建初始的小根堆,然后不断将堆顶(最小值)与堆的最后一个元素交换位置,并调整堆,直到整个数组有序。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值