python进阶篇-day09-数据结构与算法(非线性结构与排序算法)

非线性结构(树状结构)

特点: 每个节点都可以有n个子节点(后继节点) 和 n个父节点(前驱节点)

代表: 树, 图......

概述

属于数据结构之 非线性结构的一种, 父节点可以有多个子节点(后续节点)

特点

  1. 有且只有1个根节点

  2. 每个节点都可以有1个父节点及任意个子节点, 前提: 根节点除外(没有父节点)

  3. 没有子节点的节点称之为: 叶子节点

二叉树概念和性质

每个节点最多只能有2个子节点

二叉树分类:
  1. 完全二叉树: 除了最后1层, 其他层的节点都是满的

  2. 满二叉树: 包括最后1层, 所有层的节点都是满的

  3. 不完全二叉树: 某层(不仅仅是最后1层)的节点数量不满

常用二叉树:
  1. 平衡二叉树: 防止树退化成链表, 指的是: 任意节点的两颗子树的高度差不超过1

  2. 排序二叉树: 主要是对元素排序的

存储方式

更推荐使用 链表的方式来存储, 每个节点有三部分组成, 分别是: 元素域(数值域), 左子树(地址域), 右子树(地址域)

针对于, 多叉树的情况, 可以将其转成二叉树, 然后再来存储

性质
  1. 在二叉树的第i层上至多有2i-1 个结点(i>0)eg:第3层最多结点个数2^((3-1))

  2. 深度为k的二叉树至多有2k - 1个结点(k>0)eg:层次2^((3))-1= 7

  3. 对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0 = N2+1

  4. 最多有n个结点的完全二叉树的深度必为log2(n+1)

  5. 对完全二叉树,若从上至下、从左至右编号,则编号为i的结点,其左孩子编号必为2i,其右孩子编号必为2i+1,其父节点的编号必为i//2(i=1时为根,除外)

二叉树的广度优先

广度优先可以找到最短路径:

相当于层次遍历,先把第层给遍历完,看有没有终点;再把第层遍历完,看有没有重点

插入节点
  1. 初始操作:

    初始化队列、将根节点入队、准备加入到二叉树的新结点

  2. 重复执行:

    获得并弹出队头元素

    1、若当前结点的左右子结点不为空,则将其左右子节点入队列

    2、若当前结点的左右子节点为空,则将新结点挂到为空的左子结点、或者右子节点

图示

二叉树的深度优先

深度优先往往可以很快找到搜索路径:

比如:先找一个结点看看是不是终点,若不是继续往深层去找,直到找到终点。、中序,先序,后序属于深度优先算法

示例

层次(广度)遍历: 0123456789

先序遍历: 0137849256 根 左 右

中序遍历: 7381940526 左 根 右

后序遍历: 7839415620 左 右 根

图示

二叉树代码演示

# 创建节点类
class Node(object):# 初始化属性def __init__(self, item):self.item = item  # 数值域self.lchild = None  # 左子树(地址域)self.rchild = None  # 左子树(地址域)
​
​
# 创建二叉树类
class BinaryTree(object):def __init__(self, root: Node = None):self.root = root  # 根节点
​# 添加元素函数(完全二叉树)def add(self, item):# 判断根节点是否为空if self.root is None:self.root = Node(item)return# 根节点不为空, 找到缺失节点# 创建队列, 用于记录已存在的节点queue = []# 把根节点添加到队列queue.append(self.root)# 循环遍历队列, 直至 把新元素添加到合适的位置while True:# 获取队列中的第一个元素node = queue.pop(0)# 左子树为空if node.lchild is None:node.lchild = Node(item)return  # 结束添加动作else:# 左子树存在, 就将其添加到队列中queue.append(node.lchild)# 右子树为空if node.rchild is None:node.rchild = Node(item)return  # 结束添加动作else:# 右子树存在, 就将其添加到队列中queue.append(node.rchild)
​# 广度优先def breadth_travel(self):# 判断根节点是否为空if self.root is None:return  # 为空直接结束# 创建队列, 记录所有节点queue = []# 将根节点, 添加到队列中queue.append(self.root)# 只要队列长度大于0, 就说明还有节点, 循环遍历while len(queue) > 0:# 获取队列中的第一元素node = queue.pop(0)# 输出当前节点print(node.item, end='\t')# 判断当前节点的左子树是否为空if node.lchild is not None:# 不为空, 则将左子树入队queue.append(node.lchild)# 判断当前节点的右子树是否为空if node.rchild is not None:# 不为空, 则将左子树入队queue.append(node.rchild)
​# 深度优先: 先序(根左右)def preorder_travel(self, root):# 判断根节点是否不为空if root is not None:# 中序先输出根节点print(root.item, end='\t')# 递归左子树self.preorder_travel(root.lchild)# 递归右子树self.preorder_travel(root.rchild)
​# 深度优先: 中序(左根右)def mid_travel(self, root):if root is not None:self.mid_travel(root.lchild)print(root.item, end='\t')self.mid_travel(root.rchild)
​# 深度优先: 后序(左右根)def poster_travel(self, root):if root is not None:self.poster_travel(root.lchild)self.poster_travel(root.rchild)print(root.item, end='\t')
​

三. 算法

排序类相关

稳定性: 排序前后的相对位置(相同的元素位置)是否发生变化

稳定排序: 冒泡排序、插入排序、归并排序和基数排序

不稳定排序: 选择排序、快速排序、希尔排序、堆排序

冒泡排序

原理

相邻元素两辆比较, 大的往后走, 这样第一轮比较完毕后, 最大值就在最大索引处

核心
  1. 比较的总轮数 列表长度 - 1

  2. 每轮比较的总次数 列表长度 - 1 - 轮数(从0 开始)

  3. 谁和谁比较(交换) j 和 j + 1 比较

图解

代码
def buble_sort(my_list):# 定义变量n存储列表长度n = len(my_list)# 比较的轮数for i in range(n - 1):  # i: 0, 1, 2, 3# 记录交换的次数count = 0# 每轮比较的次数for j in range(n - 1 - i):  # j: 4, 3, 2, 1if my_list[j] > my_list[j + 1]:# 交换时计数器加一count += 1my_list[j], my_list[j + 1] = my_list[j + 1], my_list[j]print(f'第 {i} 轮交换了 {count} 次')# 如果当前轮次交换了0次, 则跳出外循环if count == 0:break
​
​
if __name__ == '__main__':list1 = [2, 1, 4, 5, 3]buble_sort(list1)print('list1', list1)print('-' * 21)
​list2 = [5, 3, 4, 7, 2]buble_sort(list2)print('list2', list2)
​
冒泡总结

时间复杂度: 最优O(n), 最差O(n²)

遍历一遍发现没有任何元素发生了位置交换,终止排序

算法稳定性:稳定算法

选择排序

原理

第一轮: 假设索引为0的元素时最小值, 依次和后续的元素比较, 只要比该值小, 就纪录住真正最小值的那个索引, 第一轮比较完毕后, 把最小值放到索引为0的位置即可

第二轮: 假设索引为1的元素时最小值, 依次和后续的元素比较, 只要比该值小, 就纪录住真正最小值的那个索引, 第一轮比较完毕后, 把最小值放到索引为1的位置即可

......

解释:

选择排序就是把符合要求的数据选择出来进行排序

核心
  1. 比较的总轮数 列表长度 - 1

  2. 每轮比较的总次数 i + 1 ~ 列表的最后1个元素

  3. 谁和谁比较(交换) j 和 min_index 位置的元素比较

比较过程

具体的比较过程, 假设共 5 个元素 比较的轮数 每轮比较的总次数 谁和谁比较 第0轮 4 0和1, 0和2, 0和3, 0和4 第1轮 3 1和2, 1和3, 1和4 第2轮 2 2和3, 2和4 第3轮 1 3和4

代码
def select_sort(my_list):# 定义变量n存储列表长度n = len(my_list)# 比较的轮数for i in range(n - 1):  # i: 0, 1, 2, 3# 记录最小值索引min_idx = i# 每轮比较的次数for j in range(i + 1, n):  # j: 4, 3, 2, 1# 判断min_idx后的元素是否比min_idx小if my_list[j] < my_list[min_idx]:# 将最小值索引设为jmin_idx = j# 如果最小值索引等于i说明i的位置是正确的,不交换if min_idx != i:# 交换my_list[i], my_list[min_idx] = my_list[min_idx], my_list[i]
​
​
if __name__ == '__main__':list1 = [2, 1, 4, 5, 3]select_sort(list1)print('list1', list1)print('-' * 21)
​list2 = [5, 3, 4, 7, 2]select_sort(list2)print('list2', list2)
​
选择总结

算法稳定性: 不稳定算法

时间复杂度: 最优: O(n²), 最差: O(n²)

插入排序

原理

把要排序的列表分成两部分, 第一部分是有序的(拍好序的), 第二部分是无序的(待排序的), 然后从待排序的列表中, 依次取出每个值, 插入到 排好序的列表的 合适位置 .

核心
  1. 比较的总轮数 列表长度 - 1 for i in range(1, n)

  2. 每轮比较的总次数 i ~ 0(逆向遍历) for i in range(i, 0, -1)

  3. 谁和谁比较(交换) i 和 j 的每个值 比较

比较过程

具体的比较过程, 假设共 5 个元素 比较的轮数 每轮比较的总次数 谁和谁比较 第1轮 4 1和0 第2轮 3 2和1, 2和0 第3轮 2 3和2, 3和1, 3和0 第4轮 1 4和3, 4和2, 4和1, 4和0

代码
def insert_sort(my_list):# 定义变量n存储列表长度n = len(my_list)# 比较的轮数for i in range(1, n):           # i: 1,  2,   3,     4# 每轮比较的次数for j in range(i, 0, -1):   # j: 1  2,1  3,2,1  4,3,2,1# 判断当前元素(待排序)是否比前面的元素(排好序的)小if my_list[j] < my_list[j - 1]:# 交换当前元素和当前元素的前一个元素my_list[j], my_list[j - 1] = my_list[j - 1], my_list[j]else:break
​
​
if __name__ == '__main__':list1 = [2, 1, 4, 5, 3]insert_sort(list1)print('list1', list1)print('-' * 21)
​list2 = [5, 3, 4, 7, 2]insert_sort(list2)print('list2', list2)
​
插入总结

算法稳定性: 稳定算法

时间复杂度: 最优: O(n) 最坏: O(n²)

查找类相关(二分查找)

此处只记录二分查找, 并非查找只有二分查找这一种

介绍

  1. 概述: 他是一种高效的查找类算法, 也叫: 折半查找

  2. 细节: 要被查找的列表必须是有序的

  1. 原理:

    1. 获取列表的中间位置的元素, 然后和要查找的元素进行比较

    2. 如果相等, 直接返回结果即可

    3. 如果比中间值小, 去 中间前 范围查找

    4. 如果比中间值大, 去 中间后 范围查找

递归版

def binary_search(my_list, item):n = len(my_list)if n <= 0:return Falsemid = n // 2if item == my_list[mid]:return Trueelif item < my_list[mid]:return binary_search(my_list[:mid], item)else:return binary_search(my_list[mid + 1:], item)

非递归版

def binary_search(my_list, item):# 计算列表长度n = len(my_list)# 定义初始起始位置为0start = 0# 定义初始终止位置为列表长度减1end = n - 1# 当起始位置大于终止位置时结束循环while start <= end:# 定义中间位置为起始位置加终止位置除2mid = (start + end) // 2# 判断中间索引位置的元素是否为要查找的元素if my_list[mid] == item:return True# 判断中间索引位置的元素比要查找的位置小elif my_list[mid] < item:# 设置起始位置索引为中间位置加1start = mid + 1# 判断中间索引位置的元素比要查找的位置大else:# 设置终止位置索引为中间位置减1end = mid - 1return False
​
​
if __name__ == '__main__':list1 = [1, 2, 3, 4, 5, 6, 7]print(binary_search(list1, 4))
​
​

总结

  1. 必须采用顺序存储结构

  2. 必须按关键字大小有序排列

  3. 时间复杂度: 最优: O(1) 最坏: O(logn)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/420766.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++竞赛初阶L1-15-第六单元-多维数组(34~35课)551: T456501 计算矩阵边缘元素之和

题目内容 输入一个整数矩阵&#xff0c;计算位于矩阵边缘的元素之和。 所谓矩阵边缘的元素&#xff0c;就是第一行和最后一行的元素以及第一列和最后一列的元素。 输入格式 第 1 行包含两个整数&#xff0c;分别为行数 m 和列数 n&#xff0c;两个整数之间空格隔开。 第 2 …

文本字符分割算法尝试

一、基于opencv的分割算法 import cv2 import numpy as np from matplotlib import pyplot as pltimg cv2.imread(scratch.png, 0) # global thresholding ret1, th1 cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) # Otsus thresholding th2 cv2.adaptiveThreshold(img…

Windows I/O系统

硬件存储体系 寄存器 处理器内部定义的存储体&#xff0c;它们除了存储功能&#xff0c;往往还兼有其他的能力&#xff0c;比如参与运算&#xff0c;地址解析&#xff0c;指示处理器的状态&#xff0c;等等。寄存器是由处理器内部专门的触发器电路实现的&#xff0c;处理器往…

Java代码审计篇 | ofcms系统审计思路讲解 - 篇3 | 文件上传漏洞审计

文章目录 0. 前言1. 文件上传代码审计【有1处】1.1 可疑点1【无漏洞】1.1.1 直接搜索upload关键字1.1.2 选择第一个&#xff0c;点进去分析一下1.1.3 分析this.getFile()方法1.1.4 分析new MultipartRequest(request, uploadPath)1.1.5 分析isSafeFile()方法1.1.6 分析request.…

关于支付宝小程序多规格选项的时候点击不起反应的原因分析及修改方法

解决方案&#xff1a; watch的时候&#xff0c;对于对象的赋值&#xff0c;最好用深拷贝&#xff0c;即如下图&#xff1a; watch:{ row: function (nv, ov) {var that this;that.indata.row JSON.parse(JSON.stringify(nv));//如果是对象&#xff0c;请用深入的for (va…

《OpenCV计算机视觉》—— 图像边缘检测

文章目录 一、图像边缘检测概述二、常见的图像边缘检测算法&#xff08;简单介绍&#xff09;1.sobel算子2.Scharr算子3.Laplacian算子4.Canny算子 三、代码实现 一、图像边缘检测概述 图像边缘检测是一种重要的图像处理技术&#xff0c;用于定位二维或三维图像中对象的边缘。…

一款企业网盘,支持多种文件存储方式如FTP,SFTP,MINIIO等以及跨平台管理(附源码)

前言 随着数字化转型的推进&#xff0c;企业越来越依赖于云端技术来存储、管理和共享重要的业务文件。传统的本地存储处理方案虽然可靠&#xff0c;但在灵活性、可访问性和协作方面显得力不从心。尤其在远程工作变得日益普遍的今天&#xff0c;如何高-效地管理分散团队之间的文…

Java学习Day40:大战亢金龙!(spring框架之AOP)

AOP&#xff08;面向切面变成&#xff09;&#xff1a;不改变原有代码的情况下&#xff0c;对代码进行功能添加 1.一些概念 抽取出的方法&#xff1a;通知 原始方法&#xff1a;成为连接点&#xff08;可以是程序执行中的任意位置&#xff09;&#xff0c;对应原始的一个个方…

NVDLA专题14:Runtime environment-用户模式驱动

运行时环境&#xff08;runtime environment&#xff09;包括在兼容的NVDLA硬件上运行编译神经网络的软件。 它由两部分组成: 用户模式驱动&#xff08;User Mode Driver, UMD&#xff09;: 这是应用程序的主接口&#xff0c;正如Compile library中所详述的&#xff0c;对神经…

网络药理学:1、文章基本思路、推荐参考文献、推荐视频

文章基本思路 选择一味中药或者中药复方&#xff08;常见的都是选择一味中药&#xff0c;如&#xff1a;大黄、银柴胡等&#xff09;&#xff0c;同时选择一个要研究的疾病&#xff08;如食管癌等&#xff09;获得中药的主要化学成分或者说活性成分&#xff08;有时候也以化合…

第146天:内网安全-Web权限维持各语言内存马Servlet-api类Spring类Agent类

目录 前置知识及资源 案例一&#xff1a; 权限维持-Web-内存马-PHP 案例二&#xff1a; 权限维持-Web-内存马-Python 案例三&#xff1a; 权限维持-Web-内存马-JAVA 案例四&#xff1a; 权限维持-Web-内存马-哥斯拉&冰蝎 哥斯拉 ​编辑 冰蝎 前置知识及资源 什么是…

程序员如何写笔记并整理资料?

整理笔记 word。没错&#xff0c;我也看了网上一大堆软件&#xff0c;还有git管理等等。个人认为如果笔记只是记录个人的经验积累&#xff0c;一个word就够了&#xff0c;那些notepad&#xff0c;laTex个人觉得不够简练。word。 1.word可以插入任何文件附件(目前最大的word 20…

C++笔记---list

1. list的介绍 list其实就是就是我们所熟知的链表&#xff08;双向循环带头结点&#xff09;&#xff0c;但其是作为STL中的一个类模板而存在。 也就是说&#xff0c;list是可以用来存储任意类型数据的顺序表&#xff0c;既可以是内置类型&#xff0c;也可以是自定义类型&…

六西格玛绿带培训多少钱

在探讨“六西格玛绿带培训多少钱”这一主题时&#xff0c;我们不得不深入了解六西格玛方法论在企业质量管理中的重要作用&#xff0c;以及绿带培训作为这一方法论推广和应用的关键环节。六西格玛&#xff0c;作为一种以数据驱动的管理哲学和方法论&#xff0c;旨在通过减少缺陷…

深入理解Java中的clone对象

目录 1. 为什么要使用clone 2. new和clone的区别 3. 复制对象和复制引用的区别 4.浅克隆和深克隆 5. 注意事项 1. 为什么要使用clone 在实际编程过程中&#xff0c;我们常常遇到这种情况&#xff1a;有一个对象 A&#xff0c;需要一个和 A 完全相同新对象 B&#xff0c;并…

ModuleNotFoundError: No module named ‘keras.layers.core‘怎么解决

问题 ModuleNotFoundError: No module named keras.layers.core&#xff0c;如图所示&#xff1a; 如何解决 将from keras.layers.core import Dense,Activation改为from tensorflow.keras.layers import Dense,Activation&#xff0c;如图所示&#xff1a; 顺利运行&#xf…

IOS Siri和快捷指令打开app

使用场景 需要Siri打开应用或者在自定义快捷指令打开应用&#xff0c;并携带内容进入应用。 1.创建Intents文件 1.1 依次点开File->New->File 1.2 搜索intent关键字找到 SiriKit Intent Definition File文件 1.3 找到刚才创建的Intent文件&#xff0c;点击然后New Inte…

【JS逆向学习】快乐学堂登陆接口(自定义DES加密、ddddocr验证码识别)

逆向目标 网址&#xff1a;https://www.91118.com/Passport/Account/Login接口&#xff1a;https://www.91118.com/passport/Account/LoginPost参数&#xff1a; passr 逆向过程 输入手机号、密码、验证码 点击登陆&#xff0c;多试几次&#xff0c;然后观察并比较不通请求…

MMO 地图传送,UI系统框架设计

地图传送 创建传送点 建碰撞器触发 //位置归零 建一个传送门cube放到要传送的位置&#xff08;这个teleporter1是传出的区域 这是从另一张地图传入时的传送门 创建一个脚本TeleporterObject给每个传送cube都绑上脚本 通过脚本&#xff0c;让传送门在编辑器下面还能绘制出来 …

GIT | git提交注释自动添加信息头

GIT | git提交注释自动添加信息头 时间&#xff1a;2024年9月6日10:20:11 文章目录 GIT | git提交注释自动添加信息头1.操作2.commit-msg文件 1.操作 2.commit-msg文件 #!/bin/sh # # An example hook script to check the commit log message. # Called by "git commit&q…