常见排序及查找算法

内容引用自:
【数据结构和算法】十大经典排序算法(动图演示)

算法复杂度

在这里插入图片描述

1、冒泡排序

1.1、动图演示

  • 遍历列表数据,共遍历length(列表)次,每一次的遍历都要从左到右进行两两比对,左边比右边小,那么值就调换,否则进行往后两位的比对值;
  • 每遍历一次,可以得到一个最大值(第一次遍历时最大值,后面遍历得到的应该叫次最大值)

在这里插入图片描述

1.2、代码

def bubble_sort(arr):
    for i in range(len(arr)):
        for j in range(len(arr) - 1 - i):
            if arr[j] > arr[j+1]:
                tmp = arr[j]
                arr[j] = arr[j+1]
                arr[j+1] = tmp
            # # print(arr)
            print(arr)

    return arr


if __name__ == '__main__':
    bubble_sort([9, 8, 7, 6, 5, 4, 3, 2, 1])

2、快速排序

2.1 、核心思想:

  1. 在待排序的元素任取一个元素作为基准(通常选第一个元素(arr[left]),称为基准元素(pivot),)
  2. 将待排序的元素进行分块,比基准元素大的元素移动到基准元素的右侧,比基准元素小的移动到作左侧,从而一趟排序过程,就可以锁定基准元素的最终位置
  3. 对左右两个分块重复以上步骤直到所有元素都是有序的(递归过程)

(选取pivot基准,双指针left和right分别指向第一个元素和最后一个元素,与基准进行比较,right比基准大就往左移动,否则和left位置的元素替换位置,left的往右移动,重复刚才工作,
直至双指针指向同一个位置,这样就把基准元素位置确定了,之后递归遍历基准元素的左右两边的元素即可实现排序;)
时间复杂度最好:o(nlogn) 当输入数组已经完全有序或几乎有序时最差o(n^2)
空间复杂度:最好:o(logn) 最差o(n)

2.2、静态图(来源:图解快速排序),动图不那么好理解:

在这里插入图片描述

2.3、代码:

def quick_sort(arr, left, right):
    print("原始数据:\n" + str(arr))

    if left >= right:
        return

    i = left
    j = right
    pivot = arr[left]

    while i != j:
        while (i < j) and arr[j] > pivot:  # 这里不可以等于,等于会导致1,2,1的情况,无法实现排序
            j -= 1
            
        # 比pivot小, 就将小的值替换到pivot前面去,交换值
        p = arr[i]
        arr[i] = arr[j]
        arr[j] = p

        print(arr)

        # 因为上一步arr[j]与arr[i]值调换以后,arr[i]一定是比小的,所以不用提前 i += 1,下方的while会自动给执行一次i += 1
        while (i < j) and arr[i] <= pivot:
            i += 1
		
		# 比pivot大, 就将大的值替换到pivot后面去,交换值
        p = arr[i]
        arr[i] = arr[j]
        arr[j] = p

        print(arr)

    quick_sort(arr, left, i - 1)
    quick_sort(arr, i+1, right)

    return


print(quick_sort([3, 6, 8, 10, 1, 2, 1], 0, 6))
# print(quick_sort([6, 6, 8, 10, 1, 2, 1], 0, 6))
# print(quick_sort([6, 6, 6, 10, 1, 2, 1], 0, 6))
# print(quick_sort([9, 8, 7, 6, 5, 4, 3], 0, 6))

2.4、结果:

原始数据:
[3, 6, 8, 10, 1, 2, 1]
[1, 6, 8, 10, 1, 2, 3]
[1, 3, 8, 10, 1, 2, 6]
[1, 2, 8, 10, 1, 3, 6]
[1, 2, 3, 10, 1, 8, 6]
[1, 2, 1, 10, 3, 8, 6]
[1, 2, 1, 3, 10, 8, 6]
[1, 2, 1, 3, 10, 8, 6]
[1, 2, 1, 3, 10, 8, 6]
原始数据:
[1, 2, 1, 3, 10, 8, 6]
[1, 2, 1, 3, 10, 8, 6]
[1, 1, 2, 3, 10, 8, 6]
[1, 1, 2, 3, 10, 8, 6]
[1, 1, 2, 3, 10, 8, 6]
原始数据:
[1, 1, 2, 3, 10, 8, 6]
原始数据:
[1, 1, 2, 3, 10, 8, 6]
原始数据:
[1, 1, 2, 3, 10, 8, 6]
[1, 1, 2, 3, 6, 8, 10]

3、选择排序(Selection Sort)

3.1、核心思想

选择排序(Selection-sort)是一种简单直观的排序算法。
它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

3.2、动图演示

在这里插入图片描述

3.3、代码

def selection_sort(arr):

    for i in range(len(arr)):
        print(arr)
        for j in range(i + 1, len(arr)):
            min_num = arr[i]
            if min_num > arr[j]:
                p = arr[j]
                arr[j] = arr[i]
                arr[i] = p
    # print(arr)


selection_sort([3, 2, 10, 2, 9, 6, 2])

[3, 2, 10, 2, 9, 6, 2]
[2, 3, 10, 2, 9, 6, 2]
[2, 2, 10, 3, 9, 6, 2]
[2, 2, 2, 10, 9, 6, 3]
[2, 2, 2, 3, 10, 9, 6]
[2, 2, 2, 3, 6, 10, 9]
[2, 2, 2, 3, 6, 9, 10]

4、插入排序(Insertion Sort)

4.1、核心思想

插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。
它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

4.2、动图演示

在这里插入图片描述

4.3、代码

def insertion_sort(arr):

    for i in range(1, len(arr)):
        preIdx = i - 1
        current = arr[i]

        print("第" + str(i) + "次循环输入数据:\n" + str(arr))

        # 下方这个跳出循环的部分比较巧妙,两个条件,缺一不可
        while preIdx >= 0 and arr[preIdx] > current:
            arr[preIdx + 1] = arr[preIdx]
            preIdx -= 1

            print("中间过程========" + str(arr))
        arr[preIdx + 1] = current
        print("第" + str(i) + "次循环输出结果:\n" + str(arr))

    print("最终结果:\n" + str(arr))


insertion_sort([3, 1, 10, 7, 9, 6, 2])

结果:

1次循环输入数据:
[3, 1, 10, 7, 9, 6, 2]
中间过程========[3, 3, 10, 7, 9, 6, 2]1次循环输出结果:
[1, 3, 10, 7, 9, 6, 2]2次循环输入数据:
[1, 3, 10, 7, 9, 6, 2]2次循环输出结果:
[1, 3, 10, 7, 9, 6, 2]3次循环输入数据:
[1, 3, 10, 7, 9, 6, 2]
中间过程========[1, 3, 10, 10, 9, 6, 2]3次循环输出结果:
[1, 3, 7, 10, 9, 6, 2]4次循环输入数据:
[1, 3, 7, 10, 9, 6, 2]
中间过程========[1, 3, 7, 10, 10, 6, 2]4次循环输出结果:
[1, 3, 7, 9, 10, 6, 2]5次循环输入数据:
[1, 3, 7, 9, 10, 6, 2]
中间过程========[1, 3, 7, 9, 10, 10, 2]
中间过程========[1, 3, 7, 9, 9, 10, 2]
中间过程========[1, 3, 7, 7, 9, 10, 2]5次循环输出结果:
[1, 3, 6, 7, 9, 10, 2]6次循环输入数据:
[1, 3, 6, 7, 9, 10, 2]
中间过程========[1, 3, 6, 7, 9, 10, 10]
中间过程========[1, 3, 6, 7, 9, 9, 10]
中间过程========[1, 3, 6, 7, 7, 9, 10]
中间过程========[1, 3, 6, 6, 7, 9, 10]
中间过程========[1, 3, 3, 6, 7, 9, 10]6次循环输出结果:
[1, 2, 3, 6, 7, 9, 10]
最终结果:
[1, 2, 3, 6, 7, 9, 10]

5、归并排序

5.1、思想

来源:归并排序(Merge Sort)图解,归并排序算法-学到牛牛
归并排序是建立在归并操作上的一种有效、稳定的排序算法,该算法采用非常经典的分治法(分治法可以通俗的解释为:把一片领土分解,分解为若干块小部分,然后一块块地占领征服,被分解的可以是不同的政治派别或是其他什么,然后让他们彼此异化),归并排序的思路很简单,速度呢,也仅此于快速排序

基本思路:

第一步:将序列中待排序数字分为若干组,每个数字分为一组。

第二步:将若干组两两合并,保证合并的组都是有序的。

第三步:重复第二步的操作,直到剩下最后一组即为有序数列。

详细步骤:

首先将数组中待排序数字分成若干组,每个数字为一组
在这里插入图片描述
相邻的两组进行对比,并且两两合并,保证合并后都是有序的数列,i(数字8)> j(数字4)需要交换位置(最终呈现一个升序的数组),经过比较合并后两个数存入一个空的指针里
在这里插入图片描述
在这里插入图片描述
其他组按照此方法依次合并,从8个组合并成4个组
在这里插入图片描述
继续相邻的两个组进行合并
在这里插入图片描述
定义两个变量i,j分别代表P1里的第一个值(4)和P2里的第一个值(5),i和j进行比较,i < j(4 < 5),将数字4移入p中,i向后移动一位

在这里插入图片描述
i和j进行比较,i > j(8 > 5 ),将数字5移动到p中(4的后一位),j后移一位
在这里插入图片描述
i 和j继续进行比较,i > j (8 > 7),将数字7移动到p中(5的后一位),p2中没有待排序的数字,所以比较结束,p1中剩下的数字移动到p中(7的后一位),合并结束。旁边两个序列按照同样的方式进行合并,最后得到两个有序序列,将这两个有序序列通过上面的方式继续进行合并

在这里插入图片描述
i和j进行比较,i > j(4 > 1),i不动,p2中的数字1移动到p中,j向后移动一位
在这里插入图片描述
i继续和j比较,i > j(4 > 2),数字2移动到p中(1的后一位),j向后移动一位

在这里插入图片描述
i继续和j比较,i > j(4 > 3),数字3移动到p中(2的后一位),j向后移动一位

在这里插入图片描述
i继续和j比较,i < j(4 <6),数字4移动到p中(3的后一位),i向后移动一位
在这里插入图片描述
i继续和j比较,i > j(7 >6),数字6移动到p中(5的后一位),p2中已经没有待排序的数字,所以比较结束,p1中剩下的数字移动到p中(6的后面)
在这里插入图片描述
最后得到一个有序的数列 ,归并排序结束
在这里插入图片描述

5.2、代码

def merge_sort(arr):
    # 判断是否需要继续划分  
    if len(arr) <= 1:
        return arr

    # 将数组划分为左右两部分
    mid = len(arr) // 2
    left = arr[:mid]
    right = arr[mid:]

    # 递归地对左右两部分进行排序  
    left = merge_sort(left)
    right = merge_sort(right)

    # 合并左右两部分  
    return merge(left, right)


def merge(left, right):
    result = []  # 存储合并后的结果  
    i = j = 0  # i和j分别指向左右两部分的起始位置  
    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
            # 如果左部分还有剩余元素,将其加入结果列表
    while i < len(left):
        result.append(left[i])
        i += 1
        # 如果右部分还有剩余元素,将其加入结果列表
    while j < len(right):
        result.append(right[j])
        j += 1
    return result


if __name__ == '__main__':
    print(merge_sort([3, 11, 6, 2, 5, 8]))

6、二分查找

def binary_search(arr, left, right, target):
    if left > right:
        return '-1'

    mind = (left + right) // 2

    if target > arr[mind]:
        left = mind + 1
    elif target < arr[mind]:
        right = mind - 1
    elif target == arr[mind]:
        return mind
    else:
        return "-1"

    return binary_search(arr, left, right, target)


ll = [1, 2, 3, 5, 6, 8]
print(binary_search(ll, 0, len(ll)-1, 5))

7、二叉树遍历

class TreeNode:
    def __init__(self, value = None, left = None, right = None):
        self.value = value
        self.left = left
        self.right = right


def preTraverse(root):
    if root == None:
        return None

    print(root.value)
    preTraverse(root.left)
    preTraverse(root.right)


def mindTraverse(root):
    if root == None:
        return None

    mindTraverse(root.left)
    print(root.value)
    mindTraverse(root.right)

def afterTraverse(root):
    if root == None:
        return None

    afterTraverse(root.left)
    afterTraverse(root.right)
    print(root.value)


root = TreeNode('A', TreeNode('D', TreeNode('ld'), TreeNode('rd')), TreeNode('E', TreeNode('le'), TreeNode('re')))

print("前序遍历:\n")
preTraverse(root)
print("中序遍历:\n")
mindTraverse(root)
print("后序遍历:\n")
afterTraverse(root)

未完待续…

  • 17
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值