机器学习,深度学习基础算法原理详解(数据结构部分(持续更新))

机器学习,深度学习基础算法原理详解(数据结构[持续更新])

机器学习,深度学习基础算法原理详解(图的搜索、交叉验证、PAC框架、VC-维(持续更新))

1. 链表、数组、栈、队列

链表:数据结构之一,其中的数据呈线性排列,数据添加与删除比较方便,访问较为耗时。链表中的数据是分散存储在内存中的,无需存储在连续空间。而访问数据则需要从第一个数据根据指针进行访问,而数据的增添、删除也对应其指针的改变以及增删。此外,循环列表、多向列表也是在链表尾部使用指针指向头部,或者多指向。

图1.多向列表
图2.循环列表

数组:数据结构之一,数据访问简单,而添加以及删除数据比较耗时。访问时候根据其索引,精确快速找到其位置。而增添以及删除数据需要进行索引位置的移位,删除等操作。

图3.数组

:存储的数据呈线性分布,访问、增添、删除数据整体先进后出,只能在一端操作,想要访问中间数据时,就必须通过出栈操作将目标数据移到栈顶才行。

图4.栈

队列:与栈较为类似,但是它是两端操作,下端出,上端入;取数据操作只能从下端取出操作。

图5.队列

2.哈希表、堆、二叉查找树

哈希表:类似于字典结构,数据由键和值组成,键为数据的标识符,值为数据的内容。查询数据方式则是利用哈希函数查询以及链表查询。当添加数据时,发现目标内存已被其他数据占据的情况便为哈希冲突,解决方式有:1.链地址法,即将要增添的数据存与目标内存已占数据按链表形式存放。2.开放地址法,若目标内存地址被占,那么就存放在其他位置,或者其其他位置。

图6.哈希表

:是一种图的树形结构,用以实现优先队列。优先队列可以自由添加数据,但取出数据要从最小值开始按顺序取出。结点的排列顺序为从下到上,从左到右。在增添、取出数据时候,堆依然按之前的顺序重新排序,如按父结点值小于子节点值。时间复杂度为(logn)。

图7.堆

二叉查找树:采用图的树形结构,和堆不同的是二叉查找树有两个性质:1.每个节点的值均大于其左子树上任意一个节点的值。2.每个节点的值均小于其右子树上任意一个节点的值。时间复杂度为(logn)。

图7.堆

3. 常用基础排序算法(附实现代码)

冒泡排序:比较相邻的元素,如果第一个比第二个大,就交换他们两个。对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。针对所有的元素重复以上的步骤,除了最后一个。持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
冒泡排序

代码实现:

#冒泡排序(时间复杂度(平均n^2,最好n),空间复杂度(1),稳定)
def bubble_sort(lis):
    #计算传入的列表长度
    len_lis = len(lis)
    #做双层循环
    for i in range(len_lis - 1):
        #内层循环减去已经循环的值
        for j in range((len_lis - 1) - i):
            #此处大小决定是降序还是升序
            if lis[j] < lis[j + 1]:
                lis[j],lis[j + 1] = lis[j + 1],lis[j]
    return lis
lis = [2,4,8,1,44,71,18]
print(bubble_sort(lis))

快速排序:快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。
① 从数列中挑出一个元素,称为 “基准”(pivot);
② 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
③ 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;递归到最底部时,数列的大小是零或一,也就是已经排序好了。这个算法一定会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
【算法】排序算法之快速排序

代码实现:

#快速排序(递归思想)(时间复杂度(平均nlogn,最好nlogn),空间复杂度(logn),不稳定)
def quicksort(lis):
    #计算列表长度
    len_lis = len(lis)
    #如果列表长度小于2,则返回列表
    if len_lis < 2:
        return lis
    #设置基准值为lis[0]
    basevalue = lis[0]
    #将小于基准值的元素放左侧
    left_lis = []
    # 将大于基准值的元素放右侧
    right_lis = []
    #对列表进行循环
    for i in range(1,len_lis):
        #判断值是否小于基准
        if lis[i] < basevalue:
            left_lis.append(lis[i])
        else:
            right_lis.append(lis[i])
    #递归调用
    return quicksort(left_lis) + [basevalue] + quicksort(right_lis)
lis = [1,6,3,9,12,5,10,4,7]
print(quicksort(lis))

归并排序
1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
2.设定两个指针,最初位置分别为两个已经排序序列的起始位置;
3.比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
4.重复步骤 3 直到某一指针达到序列尾;将另一序列剩下的所有元素直接复制到合并序列尾。

归并排序

代码实现:

#归并排序
def mergesort(lis):                 #定义归并排序
    len_lis = len(lis)              #计算列表长度
    if len_lis <= 1:
        return lis
    num = int(len_lis / 2)          #二分列表排序
    left_lis = mergesort(lis[:num])     #进行最小化二分列表排序
    right_lis = mergesort(lis[num:])
    return merge(left_lis, right_lis)
def merge(left_lis, right_lis):          #对最大左右列表元素排序
    l,r = 0, 0                            #定义两个指针
    result = []                          #定义一个新的空间
    while l < len(left_lis) and r < len(right_lis):         #两个指针对应元素相比较
        if left_lis[l] < right_lis[r]:                  #小的放左,大的放右,对应指针自加1
            result.append(left_lis[l])
            l += 1
        else:
            result.append(right_lis[r])
            r += 1
    result += left_lis[l:]
    result += right_lis[r:]
    return result
if __name__ == '__main__':
    list = [1,4,2,6,5,11,8,9,3]
    lis = mergesort(list)
    print(lis)

堆排序:利用大顶堆(小顶堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单。
① 将待排序的序列构造成一个最大堆,此时序列的最大值为根节点
② 依次将根节点与待排序序列的最后一个元素交换
③ 再维护从根节点到该元素的前一个节点为最大堆,如此往复,最终得到一个递增序列

【算法】排序算法之堆排序

在这里插入图片描述

代码实现:

#堆排序

from collections import deque       #利用deque列表结构追加辅助位
#直接交换堆顶元素和最后元素
def swap_param(L,i,j):
    L[i], L[j] = L[j], L[i]
    return L
#堆调整函数
def heap_adjust(L,start,end):
    temp = L[start]
    #
    i = start
    j = 2 * i

    while j <= end:
        if (j < end) and (L[j] < L[j + 1]):         #保证j取到较大子树的坐标,因为左子树大于右子树,
            j += 1                                  # 所以if不执行
        if temp < L[j]:                             #将根节点和较大的子树的值进行交换
            L[i] = L[j]
            i = j
            j = 2 * i
        else:
            break
    L[i] = temp

def heap_sort(L):
    #引入辅助空间,所以计算位数 -1
    L_length = len(L) - 1
    first_sort_count = int(L_length / 2)
    #第一个循环,将序列调整为大根堆(head_adjust函数)
    for i in range(first_sort_count):
        heap_adjust(L, first_sort_count - i, L_length)
    #第二个循环是将堆顶元素和堆末尾元素交换(swap_param函数),然后将剩下元素调整为一个大根堆函数
    for i in range(L_length - 1):
        L = swap_param(L, 1, L_length - i)
        heap_adjust(L, 1, L_length - i - 1)

    return [L[i] for i in range(1, len(L))]

def main():
    L = deque([50, 16, 30, 10, 60, 90, 2, 80, 70])
    L.appendleft(0)
    print(heap_sort(L))

if __name__ == '__main__':
    main()

堆排序递归实现:

#堆排序(递归思想)
def heap_sort(lis):
    len_lis = len(lis)
    #第一个循环,将列表构建出大顶堆
    for i in range(len_lis):
        #判断根节点与子节点大小关系,使根节点大于两个子节点
        while i > 0 and lis[(i - 1) // 2] < lis[i]:
            lis[(i - 1) // 2], lis[i] = lis[i], lis[(i - 1) // 2]
            i = (i - 1) // 2
    #第二个循环,将根节点与最下右子节点呼唤(当前二叉树最大值与最小值互换),
    #除了这两个值,整个二叉树依然是大顶堆,然后再次进行第一个循环排序,以此找出最大值
    for i in range(len_lis):
        #交换首尾位置
        lis[0], lis[len_lis - 1 - i] = lis[len_lis - 1 - i], lis[0]
        #引入flag做判断
        flag = 0
        #判断一个非叶子节点与其节点大小关系并随需要互换位置
        while 1:
            x , y = flag * 2 + 1, flag * 2 + 2
            #构建一个字典,轮询三个值的大小关系,使用递归算法轮询整个二叉树
            nums = {lis[flag] : flag}
            if x < len_lis - 1 - i:
                nums[lis[x]] = x
            if y < len_lis - 1 - i:
                nums[lis[y]] = y
            temp = max(nums.keys())
            #将当前节点与较大值交换位置
            if lis[flag] < temp:
                lis[flag], lis[nums[temp]] = lis[nums[temp]], lis[flag]
                flag = nums[temp]
            else:
                break
    return lis
lis = [8,11,4,6,2,1,10,9,8]
print(heap_sort(lis))

4. 常用基础查找算法(附实现代码)

线性查找:线性查找也叫顺序查找,这是最基本的一种查找方法,从给定的值中进行搜索,从一端开始逐一检查每个元素,直到找到所需元素的过程。

线性查找法(BFPRT)

在这里插入图片描述

代码实现:

#查找方法——线性查找(顺序查找)
def linear_search(lis, val):
    for i in range(len(lis)):
        if lis[i] == val:
            isFound = True
            print('已找到数值', val, '在第', i, '个位置')
            return i
    print('没有找到数值', val)
    return -1
lis = [2, 5, 6, 12, 0, 3, 11]
val1 = linear_search(lis, 12)
val2 = linear_search(lis, 22)
print(val1)
print(val2
print(lis.index(12))

二分查找
1.待查找的数组有序或者部分有序
2.要求时间复杂度低于O(n),或者直接要求时间复杂度为O(log n)

二分查找(折半查找)算法(原理、实现及时间复杂度)

在这里插入图片描述

代码实现:

#二分法查找
#非递归实现
def bin_search(lis, val):
    #二分排序法实现需要有序列表
    start = 0; end = len(lis) - 1
    while start <= end:
        # 判断指针位置
        mid = int((start + end) / 2)
        if lis[mid] == val:
            return mid
        elif lis[mid] > val:
            end = mid - 1
        else:
            start = mid + 1

    return -1
lis = [2, 5, 11, 13, 15, 22, 34, 45]
index1 = bin_search(lis,34)
print(index1)

#递归实现二分法
def recurbin_search(lis, start, end, val):

    mid = int((start + end) / 2)
    if (len(lis) == 0 | val < lis[start] | val > lis[end]):
        return -1
    elif lis[mid] == val:
        return mid
    elif lis[mid] < val:
        return recurbin_search(lis, mid+1, end, val)
    else :
        return recurbin_search(lis, start, mid-1, val)
lis = [1,3,5,7,8,11,13,23,34,56,78]
end = len(lis) - 1
index2 = recurbin_search(lis, 0, end, 13)
print(index2)
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

问言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值