数据结构与算法基础(python3)

时间复杂度:o(1) < o(logn) < o(n) < o(nlogn) < o(n^2) < o(n^2logn) < o(n^3)

一、递归

1. 汉诺塔:

移动次数:h(x)=2*h(x-1)+1

def hanoi(n,a,b,c): # n个圆盘,abc三个桩
        if n>0:
                hanoi(n-1,a,c,b) # 由a经过c到b
                print("moving from %s to %s" %(a,c))
                hanoi(n-1,b,a,c) # 由b经过a到c

二、 查找:index()

1. 顺序查找/线性查找:从头到尾,列表可无序

时间复杂度:o(n)

def linear_search(li,val): # li为列表,val为待查找的元素
        for ind, v in enumerate(li): # enumerate用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中
                if v==val:
                        return ind
                else:
                        return none

2. 二分查找/折半查找:与中间值比较,列表需有序

时间复杂度:o(logn)

def binary_search(li,val):
        left=0
        right=len(li)-1
        while left<=right: # 候选区有值
                mid=(left+right)//2 # 找到中间值的下标
                if li[mid]==val:
                        return mid
                elif li[mid]>val: # 待查找值在mid左侧
                        right=mid-1 # 把右指针移到mid左侧
                else: # li[mid]<val 待查找值在mid右侧
                        left=mid+1
        else:
                return none

三、 排序:sort()

1. 冒泡排序:相邻比较,前>后:交换,共n-1趟

时间复杂度:o(n^2)

def bubble_sort(li):
    for i in range(len(li)-1): # 第i趟
        exchange=False
        for j in rang(len(li)-i-1): # 指针位置
            if li[j]>li[j+1]: # 前>后:升序,前<后:降序
                li[j],li[j+1]=li[j+1],li[j] # 相邻值交换
                exchange=True
        if not exchange: # 如果没有顺序变化,提前结束排序
            return

2. 选择排序:每次遍历列表中最小值,放在第一个位置

时间复杂度:o(n^2)

def select_sort(li):
    for i in range(len(li)-1): # i是第几趟
        min_loc=i # 存储最小值位置
        for j in range(i+1,len(li)): # j是指针,li[j]是遍历的数,i+1是无需与自己比较
            if li[j]<li[min_loc]:
                min_loc=j # 找到最小值
        li[i],li[min_loc]=li[min_loc],li[i] # 最小值与无序区的值进行交换

3. 插入排序:将无序区的牌依次插入有序区

时间复杂度:o(n^2)

def insert_sort(li):
    for i in range(1,len(li)): # 遍历多少趟,i是摸到的牌的下标
        tmp=li[i]
        j=i-1 # j是手里的牌的下标
        while j>=0 and li[j]>tmp:  # 手里的牌比摸到的牌大
            li[j+1]=li[j] # j手里的牌移动到右侧
            j-=1
        li[j+1]=tmp # 如果手里的牌比摸到的牌小,摸到的牌放到手里的牌右侧

4. 快速排序:二分值作为中间值将列表分为两部分,分别递归排序

时间复杂度:o(nlogn) 

最坏情况时间复杂度: o(n^2)

def quick_sort(li,left,right):
    if left<righ:
        mid=partition(li,left,right) # 归位函数找到中间值的下标位置
        # 将列表分为两部分,分别递归
        quick_sort(li,left,mid-1)
        quick_sort(li,mid+1,right)

# partition函数原理:取出列表左侧第一个元素放入一个变量中,列表其它元素依次与该元素进行比较,比该元素小的放入左侧,大的放入右侧,当left=right时,将该元素放回列表中

def partition(li, left, right):
    tmp = li[left] # 取出列表左侧第一个元素放入一个变量中
    while left < right: # 从列表右侧(因为左侧有空位)找到比该元素小的值放入该元素位置
        while left < right and li[right] >= tmp: # 依次查找右侧元素,直到比该元素小
            right -= 1
        li[left] = li[right] # 把右边的值写到左边空位上
        while left < right and li[left] <=tmp:
            left += 1
        li[right] = li[left] # 把左边的值写到右边空位上
    li[left] = tmp # 当left=right时,将该元素放回列表中
    return left # 此时left和right是同一个值

5. 堆排序:特殊的完全二叉树,大根堆(降序),小根堆(升序)

堆的向下调整:向下依次寻找每个大于父节点的子节点,找出最大值

挨个出数:为了确保该树始终为完全二叉树,每次提取出最大值之后将最下层子节点的最右节点作为新的父节点,再进行向下调整找出最大值

构造堆的过程:先调整最下层的非叶子节点的子树,再依次扩大需调整的树

堆排序过程:1.建立堆 --> 2.得到堆顶元素为最大元素 --> 3.去掉堆顶,将堆最后一个元素放到堆顶,通过一次调整重新使堆有序 --> 4.堆顶元素为第二大元素 --> 5.重复步骤3,直到堆为空

内置模块:heapq

常用函数:heapify(x),heappush(heap, item),heappop(heap)

时间复杂度:o(nlogn)

'''
二叉树顺序存储方式的(列表)原理:i是层数
通过父节点找子节点:
父节点和左子节点的下标之间的关系:i --> 2i+1
父节点和右子节点的下标之间的关系:i --> 2i+2
通过子节点找父节点:i --> (i-1)//2
'''

# 定义一个方法用于调整:看父节点去哪个子节点,时间复杂度为o(logn)
def sift(li, low, high): # high是堆的最后一个元素的下标,low是堆的第一个元素的下标
    i = low # 第一个元素的下标
    j = 2 * i + 1 # 第一个元素的左子节点的下标
    tmp = li[low] # 把堆顶的值存入一个临时变量中
    while j <= high: # 只要j位置有值,一直循环
        if j + 1 <= high and li[j+1] > li[j]: # 如果右子节点存在,并比左子节点大
            j = j + 1 # j指向右子节点
        if li[j] > tmp:
            li[i] = li[j]
            i = j # 向下调整一层
            j= 2 * i + 1
        else: # tmp更大时,将tmp放到i的位置
            li[i] = tmp
            break
    else: # 当j > high时,j指向树的负1层(越界),没有对应的j值与tmp进行比较,直接将tmp值放入i处
        li[i] = tmp


# 定义堆排序:建立堆并调整堆并挨个出数,时间复杂度为o(nlogn)
def heap_sort(li):
    n = len(li)

    # 建立堆,时间复杂度为o(n/2*logn)-->o(nlogn)
    for i in range((n-2)//2, -1, -1): # 通过子节点找父节点: i=n-1, (i-1)//2 = (n-1-1)//2;遍历范围至-1;步长-1

        sift(li, i, n-1) # high的作用是确保i是最后一层,i不会再超过high,high始终指向整个堆的最后一个元素n-1

    # 挨个出数,时间复杂度为o(nlogn)
    for i in range(n-1, -1, -1): # i指向当前堆的最后一个元素
        li[0], li[i] = li[i], li[0] # 堆顶与堆最后一个元素做交换
        sift(li, 0, i-1) # i-1是新的high,即当前堆的最后一个元素下标为i-1


li = [i for i in range(100)]
import random
random.shuffle(li)
print(li) # 打印原无序列表

heap_sort(li)
print(li) # 打印排序后列表
# 使用内置模块和函数实现堆排序

import heapq # q是queue队列,用堆实现优先队列
import random

# 生成一个随机列表
li = list(rang(100))
random.shuffle(li)

# 建立小根堆
heapq.heapify(li)

# 建立堆排序:每次弹出最小元素
n = len(li)
for i in range(n):
    print(heapq.heappop(li), end=',')

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
数据结构与算法(Python) 一、引入概念 1-01算法引入 1-02 时间复杂度与大O表示法 1-03-最坏时间复杂度与计算规则 1-04-常见时间复杂度与大小关系 1-05-代码执行时间测量模块 1-06-Python列表类型不同操作的时间效率 1-07-Python列表与字典操作的时间复杂度 1-08-数据结构引入 二、顺序表 2-01 内存、类型本质、连续存储 recv 2-02 基本顺序表与元素外围顺序表 recv 2-03 顺序表的一体式结构与分离式结构 recv 2-04 顺序表数据区替换与扩充 recv 三、栈 3-01 栈与队列的概念 3-02 栈的实现 3-03 队列与双端队列的实现 四、链表 4-01 链表的提出 4-02 单链表的ADT模型 4-03 Python中变量标识的本质 4-04 单链表及结点的定义代码 4-05 单链表的判空、长度、遍历与尾部添加结点的代码实现 4-06 单链表尾部添加和在指定位置添加 4-07 单链表查找和删除元素 4-08 单链表与顺序表的对比 4-09 单向循环链表遍历和求长度 4-10 单向循环链表添加元素 4-11 单向循环链表删除元素 4-12 单向循环链表删除元素复习及链表扩展 4-13 双向链表及添加元素 4-14 双向链表删除元素 五、排序与搜索 5-01 排序算法的稳定性 5-02 冒泡排序及实现 5-03 选择排序算法及实现 5-04 插入算法 5-05 插入排序 5-06 插入排序2 5-07 希尔排序 5-08 希尔排序实现 5-09 快速排序 5-10 快速排序实现1 (1) 5-10 快速排序实现1 5-11 快速排序实现2 5-12 归并排序 5-13 归并排序 代码执行流程 5-14 归并排序时间复杂度及排序算法复杂度对比 5-15 二分查找 5-16 二分查找时间复杂度 六、树和树的算法 6-01 树的概念 6-02 二叉树的概念 6-03 二叉树的广度优先遍历 6-04 二叉树的实现 6-05 二叉树的先序、中序、后序遍历 6-06 二叉树由遍历确定一棵树 ———————————————— 版权声明:本文为CSDN博主「dwf1354046363」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/dwf1354046363/article/details/119832814
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

想要好好撸AI

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

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

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

打赏作者

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

抵扣说明:

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

余额充值