查找和排序算法

这篇博客详细介绍了各种排序算法,包括直接插入排序、希尔排序、冒泡排序、快速排序、直接选择排序和堆排序。对于每种排序算法,都提供了基本思想、关键技术和代码实现。此外,还提到了归并排序和基数排序,是理解排序算法的好资源。
摘要由CSDN通过智能技术生成

一、排序算法

基础类排序

直接插入排序

代码实现
def insert_sort(arr):
    length = len(arr)
    for i in range(1, length):
        j = i - 1
        temp = arr[i]
        while j >= 0 and temp < arr[j]:
            arr[j + 1] = arr[j]
            j -= 1
        else:
            arr[j + 1] = temp
    return arr


if __name__ = '__main__':
	a = [2, 4, 6, 7]
	print(insert_sort(a))

希尔排序

技术要点

希尔排序是在直接插入排序的基础上做的改进,也就是将带排序的序列按固定增量分成若干组,等距者在同一组中。然后再在组内进行直接插入排序。这里固定增量从n/2开始,以后每次缩小一半。

代码实现
def shell_sort(arr, length_arr):
    dk = int(length_arr / 2)
    while dk >= 1:
        # 下面这个for循环可以起到为每一个分组执行直接插入排序的作用
        # 第一轮:它将每一个分组的第二个数字和每个分组的第一个数组做插入排序
        # 第二轮:它将每个分组的第三个数字和前两个数组做插入排序
        # 依次类推
        for i in range(dk, length_arr):
            position = i
            index = i
            temp = arr[position]
            j = int(index / dk)
            index = index - j * dk
            while position > index and temp < arr[position - dk]:
                arr[position] = arr[position - dk]
                position = position - dk
            else:
                arr[position] = temp
        dk = int(dk / 2)
    return arr

交换类排序

冒泡排序

代码实现
def bubble_sort(arr):
    length = len(arr)
    for i in range(length - 1):
        flag = False
        for j in range(length - 1 - i):
            if arr[j] > arr[j + 1]:
                flag = True
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
        if not flag:
            break
    return arr

快速排序

思路

冒泡排序中,在扫描的过程中只比较两个相邻的两个元素,所以在交换两个相邻元素时只能消除一个逆序。其实也可以对两个不相邻的元素进行交换,这样做的好处是能消除待排序记录中的多个逆序,从而加快排序速度。
快速排序的基本思路如下:
1)从待排序记录中选取一条记录,通常选取第一条记录,将其关键字设置为K1。
2)将关键字小于K1的记录移到K1前面,将关键字大于K1的记录移到K1后面,结构记录被分成两个子表
3)将K1插入到其分界线的位置。
通常将上述过程称为一趟快速排序,通过一次划分之后,会以关键字K1的这条记录作为分界线,将待排序序列分成两个子表。可以对分割后的字表继续按照上述的原则进行分割,知道所有子表的长度不超过1未知。
快速排序法基于分治的思想,具体的步骤如下:
1)从数列中挑选出一个元素,将该元素称为基准元素
2)扫描一遍数列,将所有比基准元素小的元素排在基准元素的前面,将所有比基准元素大的元素排在基准元素的后面。
3)使用递归将各子序列划分为更小的序列,直到把小于基准元素的子数列和大于基准元素的子数列排序完。

代码实现
def quick_sort(arr):
    if len(arr) == 1 or len(arr) == 0:
        return arr
    base = arr[0]
    base_arr = [item for item in arr if item == base]
    low_arr = [item for item in arr if item < base]
    high_arr = [item for item in arr if item > base]
    return quick_sort(low_arr) + base_arr + quick_sort(high_arr)

选择排序

在选择排序中,每一趟从待排序的记录中选出关键字最小的记录,顺序的放在已排序好的子文件最后,直到排序完全部记录为止。常用的选择排序有两种,分别是直接选择排序和堆排序。

直接选择排序

代码实现
def select_sort(arr):
    length = len(arr)
    for i in range(length - 1):
        smallest = i
        for j in range(i + 1, length):
            # 找到比当前值小的index,则进行两值交换
            if arr[j] < arr[smallest]:
                arr[smallest], arr[j] = arr[j], arr[smallest]
    return arr

堆排序

思路

堆排序的具体做法是:将所有待排序的记录的关键字存放在数组r[1…n]中,将r用一颗完全二叉树的顺序表示。每个节点表示一条记录,第一条记录r[1]作为二叉树的跟,后面的各条记录r[2…n]依次逐层从左到右顺序排列,任意r[i]的左孩子是r[2i]右孩子是r[2i+1]双亲是r[i/2]。调整这颗完全二叉树,使得各节点关键字的值满足以下条件。

r[i].key >= r[2i].key且r[i].key >= r[2i+1].key (i=1, 2,,,[n/2])

将满足上述条件的完全二叉树称为堆。
堆排序的过程主要需要解决以下几个问题:
1)如何重建堆
2)如何用任意序列建初堆
3)如何用堆进行排序

  • 重建堆
    重建堆的过程非常简单,只需要以下两个移动步骤即可。
    (1)移出完全二叉树跟节点中的记录,该记录称为待调整记录,此时的跟节点接近于空节点。
    (2)从空节点的左子,右子中选出一条关键字较小的记录,如果该记录的关键字小于待调整记录的关键字,则将该记录上移至空节点。此时原来那个关键字较小的子节点相当于空节点。
    重复以上步骤,直到空节点的左子,右子的关键字均不小于待调整记录的关键字为止,此时将带调整记录放入到空节点即可完成重建。通过以上调整方法,实际上是对待调整记录实现了逐步向下筛选出来,所以上述过程称为“筛选”法。
  • 用任意序列初建堆
    将任意序列看成完全二叉树,可以利用筛选法,自底层向上逐层把所有子树调整为堆,直到将整个二叉树调整为堆。可以确定最后一个非叶节点位于第[n/2]个元素,n为二叉树节点数目。所以筛选必须冲第n/2个元素开始,逐层向上倒退,直到跟节点为止。
  • 利用堆进行排序
    (1)将待排序记录按照堆的定义建立一个初堆,并输出堆顶元素,
    (2)调整剩余的记录序列,使用筛选法将前n-1个元素重新筛选,以便建成一个新堆,然后输出堆顶元素。
    (3)重复执行步骤2,实现n-1此筛选,这样新筛选出来的堆会越来越小。而新堆后面的有序关键字会越来越多,最后是待排序列称为一个有序序列,这个过程称为堆排序。

可以参考一下连接来理解堆排序
https://blog.csdn.net/qq_34840129/article/details/80638225

代码实现
# -*-coding:utf-8-*- 


# 调整堆
def adjust_heap(arr, i, size):
    left = 2 * i + 1
    right = 2 * i + 2
    m = i
    if i < size / 2:
        if left < size and arr[left] > arr[m]:
            m = left
        if right < size and arr[right] > arr[m]:
            m = right
        if m != i:
            arr[m], arr[i] = arr[i], arr[m]
            adjust_heap(arr, m, size)


# 创建堆
def build_heap(arr, size):
    for i in range(0, (int(size / 2)))[::-1]:
        adjust_heap(arr, i, size)


def heap_sort(arr):
    size = len(arr)
    build_heap(arr, size)
    for i in range(0, size)[::-1]:
        arr[0], arr[i] = arr[i], arr[0]
        adjust_heap(arr, 0, i)
    return arr


if __name__ == '__main__':
    a = [9, 4, 5, 2, 3, 1, 11, 19, 12, 15, 18, 20, 22, 30]
    print(heap_sort(a))

归并排序

思想

  • 自底向上的方法
  • 自顶向下的方法
    使用自顶向下的方法更加简洁。
    假设归并当前的区间是R[low, heigh],分治法的三个步骤如下。
    1)分解:将当前区间一分为二,即求分裂点。
    2)求解:递归地对两个子区间R[low, mid]和R[mid+1, high]进行归并排序。
    3)组合:将已排序的两个区间R[low, mid]和R[mid+1, high]归并为一个有序的区间。

代码实现

# -*-coding:utf-8-*- 


def merge_sort(arr):
    if len(arr) <= 1:
        return arr
    mid = int(len(arr) / 2)
    left = merge_sort(arr[0:mid])
    right = merge_sort(arr[mid:])
    return merge(left, right)


def merge(left, right):
    result = []
    i, j = 0, 0
    while i < len(left) and j < len(right):
        l = left[0]
        r = right[0]
        if l <= r:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    if i < len(left):
        result.extend(left[i:])
    if j < len(right):
        result.extend(right[:])
    return result


if __name__ == '__main__':
    a = [9, 4, 5, 2, 3, 1, 11, 19, 12, 15, 18, 20, 22, 30]
    print(merge_sort(a))

基数排序

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值