I-03数据结构与算法(python版)

news2024/11/19 9:38:40

最近学习数据结构,对于从未接触过数据结构的我来说,老师不仅讲解理论,还有代码的逐层分析,非常不错,受益匪浅!!!(以下是学习记录)

数据结构与算法(Python语言描述)——完整顺序版_哔哩哔哩_bilibili

目录

1.重点+基础语法

2.时间复杂度(主要关注最坏时间复杂度) 

3.timeit,list,dic内置函数

4.数据结构

5.顺序表

5.1 顺序表的2个形式

5.2 顺序表的结构与实现

5.3 顺序表数据区扩充

5.4 顺序表的操作

5.5 python_list使用顺序表数据结构

6.链表

6.1 链表概念 

6.2 单链表的实现

6.3 链表与顺序表的对比

6.4 双向链表

6.5 单向循环链表

7.栈

8.队列

9.排序


1.重点+基础语法

  1. python语言只要是给出的变量名,里边存储的都是地址值(可以把类,函数,付给变量a)。
    如a=5 a=“s” a=Person() a=f 方法。
  2. time.time()

2.时间复杂度(主要关注最坏时间复杂度) 

不同方法间的复杂度

import time
start= time.time()
for i in range(0,1001):
    for j in range(0,1001):
        for k in range(0,1001):
            if i+j+k==1000 and i**2+j**2==k**2:
                print(i,j,k)
end = time.time()
print("总开销:",end-start)#总开销: 126.49699997901917

start1= time.time()
for i in range(0,1001):
    for j in range(0,1001):
        k=1000-i-j
        if i**2+j**2==k**2:
            print(i,j,k)
end1= time.time()
print("总开销:",end1-start1)#总开销: 1.0120000839233398
  1. T(n)时间复杂度,n执行的步数
    大O表示法,只记录最显著特征O(n)=nxn
  2. 最坏时间复杂度(平常说的就是这个)
    比如对一个list排序,无序的复杂度要高于有序。

    基本步骤:顺序,条件(取T最大值),循环
    li.append()不能看成一步,只有分析函数中的封装才能看到append的时间复杂度


3.timeit,list,dic内置函数

timeit模块

from timeit import Timer
def test():
    l=[i for i in range(1000)]
t=Timer("test()","from __main__ import test")##1函数名,2import,因为这个Timer不一定在这里运行

print(t.timeit(number=10000))

对于上例使用不同方法实现时:

1.
('list(range(1000)) ', 0.014147043228149414, 'seconds')
('l = [i for i in range(1000)]', 0.05671119689941406, 'seconds')
('li.append ', 0.13796091079711914, 'seconds')
('concat加 ', 1.7890608310699463, 'seconds')
2.由于数据的存储方式不同,导致插头部和尾部
append()#2.159s
insert(0,i)#30.00s
pop(end)#0.00023,对尾部弹出
pop(0)#1.91

4.数据结构

        数据是一个抽象的概念,将其分类后得到程序语言的基本类型,如int,float,char。数据结构指对数据的一种封装组成,如高级数据结构list,字典。数据结构就是一个类的概念,数据结构有顺序表、链表、栈、队列、树

        算法复杂度只考虑的是运行的步骤,数据结构要与数据打交道。数据保存的方式不同决定了算法复杂度。

        程序 = 数据结构 + 算法
        总结:算法是为了解决实际问题而设计的,数据结构是算法需要处理的问题载体

        抽象数据类型(Abstract Data Type):是指一个数学模型以及定义在此数学模型上的一组操作。

class Stu(object):
    def adds(self):pass
    def pop(self):pass
    def sort(self):pass
    def modify(self):pass
  

== 代码编写注意==

2.对于链表要先接入新的node,再打断原来的,要注意顺序

下面讲的各种表都是一种数据的封装结构

5.顺序表

顺序表+链表=线性表:一根线串起来,两种表都是用来存数据的

5.1 顺序表的2个形式

  1. 计算机存储
    计算机最小寻址单位是1字节,就是一个字节,才有一个地址,所有的地址都是统一大小0x27 4个字节。
  2. 元素内置顺序表
    对于存放一个含有相同类型元素的list来讲,用顺序表封装成一个数据结构。
  3. 元素外置顺序表


    元素内置顺序表,是指存储的数据类型都是一样,这样为每个元素开辟的空间都是一样大的,在根据index找元素的时候
    如list1=[1,2,3], 可以根据list的首地址0x12,很容易计算要查询元素的物理地址=0x12+index x 4.
    元素外置, 指存的数据类型不一样,如list2=[1,3,“b”,4,“ccc”]

 

5.2 顺序表的结构与实现

对于python来讲已经做好封装,不需要写容量,元素个数。

元素存储区替换

  • 一体式结构由于顺序表信息区与数据区连续存储在一起,所以若想更换数据区,则只能整体搬迁,即整个顺序表对象(指存储顺序表的结构信息的区域)改变了。
  • 分离式结构若想更换数据区,只需将表信息区中的数据区链接地址更新即可,而该顺序表对象不变。
  • so常用的是分离式

 

5.3 顺序表数据区扩充

如果数据要来回增,删,导致空间不稳定,所以有了策略:

5.4 顺序表的操作

5.5 python_list使用顺序表数据结构

  1. 表头与数据分离式
  2. 因为一个list中有int,也有字符所以用的是元素外置
  3. 动态顺序中的倍数扩充

6.链表

6.1 链表概念 

# cur做判断,逻辑(不是指针)走到最后一个元素时,里面的方法体是执行的
# 用cur.next做判断,while循环中是不执行的
# 如果发现少一次执行语句,可以手动打印,就不用完全在while循环中执行

 java,c语言是需要中间变量temp,才能完成交换,只有python可以直接交换。

6.2 单链表的实现

  • cur:指针地址
  • cur.elment:地址中的元素
  • cur=self._head先提出等式右边地址,再给cur

多写几次单链表,有助理解,链表的运行过程。

##1.单链表的节点,里面存放element区和next==>相当于元组(element,next)
class SingleNode(object):
    def __init__(self,item):
        ##item存放数据元素
        self.item=item
        ##next是下一个节点的标识
        self.next=None
    
##2.单链表数据结构类,具有以下功能==>相当于python中的list数据结构类,同时它页具有以下功能
class SingleLinkList(object):
    def __init__(self):
        self._head=None#私有属性,head=None,说明p指向的单链表中没有node

    def is_empty(self):
        return self._head==None

    def length(self):
        cur=self._head
        count=0
        while cur!=None:
            count+=1
            cur=cur.next
        return count

    def travel(self):
        ##遍历链表
        cur=self._head
        while cur!=None:
            print(cur.item)
            cur=cur.next
        print("")

    def add(self,item):
        ##头部添加元素
        node=SingleNode(item)
        node.next=self._head
        self._head=node
        
    def append(self,item):
        ##尾部添加元素
        node=SingleNode(item)
        if self.is_empty():
            self._head=node
        else:
            cur=self._head
            while cur.next!=None:
                cur=cur.next
            cur.next=node

if __name__=="__main__":
    li=SingleLinkList()
    print(li.is_empty())
    print(li.length())
    node=SingleNode(3)
    li.append(111)
    li.travel()

指定位置添加元素:

    def insert(self, pos, item):
        """指定位置添加元素"""
        # 若指定位置pos为第一个元素之前,则执行头部插入
        if pos <= 0:
            self.add(item)
        # 若指定位置超过链表尾部,则执行尾部插入
        elif pos > (self.length()-1):
            self.append(item)
        # 找到指定位置
        else:
            node = SingleNode(item)
            count = 0
            # pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置
            pre = self._head
            while count < (pos-1):
                count += 1
                pre = pre.next
            # 先将新节点node的next指向插入位置的节点
            node.next = pre.next
            # 将插入位置的前一个节点的next指向新节点
            pre.next = node

查找节点是否存在:

def search(self,item):
        """链表查找节点是否存在,并返回True或者False"""
        cur = self._head
        while cur != None:#一直往后走,起到遇到none停止
            if cur.item == item:
                return True
            cur = cur.next
        return False

删除节点:

def remove(self,item):
        """删除节点"""
        cur = self._head
        pre = None
        while cur != None:
            # 找到了指定元素
            if cur.item == item:
                # 如果第一个就是删除的节点
                if not pre:
                    # 将头指针指向头节点的后一个节点
                    self._head = cur.next
                else:
                    # 将删除位置前一个节点的next指向删除位置的后一个节点
                    pre.next = cur.next
                break
            else:
                # 继续按链表后移节点
                pre = cur
                cur = cur.next

6.3 链表与顺序表的对比

链表只能记录头节点地址,因此在访问,尾部插,中间查时,都需要从头节点,遍历过去,所以复杂度O(n):

  1. 链表可以利用离散的空间,顺序表只能开辟完整的连续空间,只要list不够,必须重新开辟
  2. 链表时间花费到遍历地址上,顺序表花费到表的复制搬迁

6.4 双向链表

对于前面单向的,当前node不能查看其前面node的信息,所以引入双向。添加,删除node时,要保证每个node中的P,N都 给上值,如:中间插入.

def add(self, item):
    """头部插入元素"""
    node = Node(item)
    if self.is_empty():
        # 如果是空链表,将_head指向node
        self._head = node
    else:
        # 将node的next指向_head的头节点
        node.next = self._head
        # 将_head的头节点的prev指向node
        self._head.prev = node
        # 将_head 指向node
        self._head = node

尾部插入元素:

def append(self, item):
        """尾部插入元素"""
        node = Node(item)
        if self.is_empty():
            # 如果是空链表,将_head指向node
            self._head = node
        else:
            # 移动到链表尾部
            cur = self._head
            while cur.next != None:
                cur = cur.next
            # 将尾节点cur的next指向node
            cur.next = node
            # 将node的prev指向cur
            node.prev = cur

中间插入:

6.5 单向循环链表

  • 由于是循环列表,最后的尾结点不再是None结束,而是指向self._head
  • 由于一开始将cur = self._head设成游标,所以判断语句只能是cur.next
  • while cur.next != self._head
    使用cur.next不能进到循环体,会导致少一次打印,可以手动打印

length(self)返回链表长度:

def length(self):
        """返回链表的长度"""
        # 如果链表为空,返回长度0
        if self.is_empty():
            return 0
        count = 1
        cur = self._head#指针启动地址
        while cur.next != self._head:#因为循环链表最后一个node要带有self._head,所以通过判断是否有self._head来看是否一个循环结束
            count += 1
            cur = cur.next
        return count

头部添加节点:

def add(self, item):
        """头部添加节点"""
        node = Node(item)
        if self.is_empty():
            self._head = node
            node.next = self._head
        else:
            #添加的节点指向_head
            node.next = self._head
            # 移到链表尾部,将尾部节点的next指向node
            cur = self._head
            while cur.next != self._head:
                cur = cur.next
            cur.next = node
            #_head指向添加node的
            self._head = node

7.栈

栈=杯
顺序表,链表是用来存数据的
栈和队列不考虑数据是如何存放的,栈stack,队列是一种容器,执行什么样的操作,抽象结构。

 

#利用前面封装好的顺序表的二次开发
class Stack(object):
    """栈"""
    def __init__(self):#初始化的时候要生成一个容器,顺序表就是python中的list,然后再执行操作,可将list设成私有的,self.__items = []这样就不能修改原来的list容器
         self.items = []

    def is_empty(self):
        """判断是否为空"""
        return self.items == []#右边是一个判断返回True
        
#对于存放的数据结构是顺序表来讲,尾部压栈出栈复杂度为o(1),对于链表来讲,头部复杂度为o(1),所以要考虑
    def push(self, item):#从尾部压,从尾部取
        """加入元素"""
        self.items.append(item)

    def pop(self):
        """弹出元素"""
        return self.items.pop()

    def peek(self):
        """返回栈顶元素"""
        return self.items[len(self.items)-1]

    def size(self):
        """返回栈的大小"""
        return len(self.items)

if __name__ == "__main__":
    stack = Stack()
    stack.push("hello")
    stack.push("world")
    stack.push("itcast")
    print stack.size()
    print stack.peek()
    print stack.pop()
    print stack.pop()
    print stack.pop()

8.队列

 

#因为出入队总有一个复杂度为N,所以考虑是出队用的多,还是入队多,再写程序
class Queue(object):
    """队列"""
    def __init__(self):#空列表保存队列
        self.items = []

    def is_empty(self):
        return self.items == []

    def enqueue(self, item):
        """进队列"""
        self.items.insert(0,item)

    def dequeue(self):
        """出队列"""
        return self.items.pop()

    def size(self):
        """返回大小"""
        return len(self.items)

if __name__ == "__main__":
    q = Queue()
    q.enqueue("hello")
    q.enqueue("world")
    q.enqueue("itcast")
    print q.size()
    print q.dequeue()
    print q.dequeue()
    print q.dequeue()

双端队列:两个栈尾部放一起

 

9.排序

接下来有兴趣了,继续更新。。。。。。

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DEiT:通过注意力训练数据高效的图像transformer 蒸馏

摘要 最近&#xff0c;纯基于注意力的神经网络被证明可以解决图像理解任务&#xff0c;如图像分类。这些高性能的是使用大型基础设施预先训练数以亿计的图像&#xff0c;从而限制了它们的采用。 本文仅通过在Imagenet上训练&#xff0c;产生有竞争力的无卷积transformer。我们…

react原理-transition概念

在react18之中&#xff0c;引入了transition的概念。而且有一个新的api和两个新的hooks startTransitionuseTransitionuseDeferredValue 场景应用&#xff1a; 比如通过输入框输入内容更新列表内容&#xff0c;对于用户来说&#xff0c;输入框输入之后立马反馈的优先级是高过…

VS ChatGPT 中文版插件安装

1.打开Visual Studio Code 2.搜索chatGpt中文版 3.安装完后&#xff0c;重启一下软件 有国模式和国外模式&#xff0c;更多的教程请看插件作者的视频教程

分布式事物

Seata实践 XA模式 AT模式 TCC模式 性能 Saga模式 高可用------集群的形式 Seata实践解决方案 解决方式 Seata 引入服务协调者模式 实践步骤&#xff1a; 分布式事物的入口方法&#xff0c;会调用其他的微服务&#xff0c;每次调用的服务都是一个分支事物调用了多少个分支事…

SpringSecurity 认证实现

在之前一篇 博客 已经说明了 SpringSecurity 认证与授权的原理。这篇用来具体实现一下。 1、新建SecurityConfig 并创建认证管理器 Bean public AuthenticationManager authenticationManager() {... }2、新建认证提供者 Configuration public class SystemUserPasswordAuth…

Oracle项目管理之PrimaveraUnifier组织-业主/合作伙伴公司

目录 一、业主公司 二、合作伙伴公司 三、成员公司 Oracle Primavera Unifier 是企业项目协同管理系统&#xff0c;在国际化项目管理中&#xff0c;在进行常规的业务管理之外&#xff0c;对合同公司/EPC或分包供应商也有一定的管理要求&#xff0c;在Unifier中为了更好的实现…

sja1000 CAN驱动学习、调试记录(基于PeliCan Mode)

一、基础知识 网上讲sja1000 CAN总线控制器的资料很多&#xff0c;这里放一个引路贴&#xff1a;(151条消息) CAN总线控制器SJA1000_FATE的博客-CSDN博客_sja1000 BasicCAN Mode&#xff1a;仅支持11位的ID。 PeliCan Mode&#xff1a;在扩展模式下&#xff0c;允许使用 11 位 …

找出DataFrame中指定数据类型的列:select_dtypes()函数

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 找出DataFrame中指定数据类型的列 select_dtypes()函数 选择题 下列说法错误的是? import pandas as pd myDF pd.DataFrame({A:[1,2],B:[1.0,2.0],C:[a,b]}) print("【显示】myDF&qu…

leecode#同构字符串#反转链表

题目描述&#xff1a; 给定两个字符串 s 和 t &#xff0c;判断它们是否是同构的。 如果 s 中的字符可以按某种映射关系替换得到 t &#xff0c;那么这两个字符串是同构的。 每个出现的字符都应当映射到另一个字符&#xff0c;同时不改变字符的顺序。不同字符不能映射到同一…

ReentrantLock详解

JUC中的锁API 在juc中有一个Lock接口他的作用和synchronized相似都是为了保证线程安全性提供的解决方案 Lock中定义了一系列释放锁和抢占锁相关的API lock() 抢占锁资源 如果当前线程没有抢占到锁 则阻塞 tryLock() 尝试抢占锁资源 如果抢占成功则返回true 否则返回false unlo…

简单的深度活体智能记忆模型

🍿*★,*:.☆欢迎您/$:*.★* 🍿 正文

基于Antd Input组件自定义Input的成功状态

前言 Ant Design的Input组件的有一个状态的Api 需求 公司自研UI组件&#xff0c;在Antd的基础上进行开发。其中Input组件除了警告与错误状态外&#xff0c;还增加了成功的状态。如下图⬇️ 开发实现 方案一&#xff1a;覆盖CSS样式 一开始准备通过判断状态来增加类名&am…

软件工程习题

软件工程第一章 软件与软件工程作业第二章 可行性研究作业第三章 需求分析作业第四章 总体设计作业第五章 详细设计作业第六章 软件编码测验第七章 软件测试作业选择判断简答题第一章 软件与软件工程作业 一、单选题&#xff08;共7题&#xff0c;58.1分&#xff09; 1、软件是…

刷题13-左右两边子数组的和相等

题目012-左右两边子数组的和相等 思路&#xff1a;用到了三个循环&#xff0c;从头到尾遍历数组&#xff0c;比较左右两边数组的和是否相等&#xff0c;当然这种思路时间复杂度也比较高 核心代码&#xff1a; class Solution {public int pivotIndex(int[] nums) {int sum1,…

6.2 、MyBatis 高级映射(resultMap 标签多表联查 , 一对多,多对一关系)

文章目录一、实现多表联查&#xff08;association 标签&#xff09;1、实现多对一关系结果集映射二、实现多表联查&#xff08;collection 标签&#xff09;一、实现多表联查&#xff08;association 标签&#xff09; association 标签&#xff1a; 实现一对一&#xff0c;多…

因果推断1--基本方法介绍(个人笔记)

目录 一、因果推断介绍 1.1 什么是因果推断 1.2为什么研究因果推断 1.3因果推断阶梯 1.4因果推断问题分类 二、因果推断理论框架 2.1 定义&#xff08;这些定义后面会经常用到&#xff09; 2.2 Assumptions&#xff08;三大基本假设&#xff09; 三、因果效应估计 3.1 因果效应…

JavaEE【Spring】:SpringBoot 配置文件

文章目录一、配置文件的作用二、配置文件的格式1、注意2、说明三、properties 配置文件说明1、基本语法2、读取配置文件① 注意3、优缺点四、yml 配置文件说明1、基本语法2、yml 使用进阶① yml 配置不同数据类型及 nullⅠ. yml 配置读取Ⅱ. 练习a. 值为 null 的配置b. 根本不存…

利用云服务器发布项目

前言 平时开发我会写一些小demo&#xff0c;我自己觉得有用的会集中起来形成一个项目&#xff0c;本来想利用gitee的gitee page直接部署出来&#xff0c;但后面了解了下&#xff0c;它只支持官网之类的静态页面&#xff0c;无法与后台数据交互&#xff0c;想要完整的服务还是得…

数据分析业务场景 | 用户画像

一.概况 定义 是根据用户的一系列行为和意识过程建立起来的多维度标签&#xff1b;是根据用户人口学特征&#xff0c;网络浏览内容&#xff0c;网络社交活动和消费行为等信息而抽象出的一个标签化的用户模型&#xff1b;首要任务&#xff1a;根据业务需求整理和数据情况分析建…

Springboot redirect重定向使用RedirecAtrributes传递数据

参考资料 【转载】关于重定向RedirectAttributes的用法RedirectAttributes 的使用 目录前期准备一. RedirecAtrributes重定向传参三. 重定向目标页面接收参数前期准备 ⏹配置文件 server:servlet:context-path: /jmw⏹访问url http://localhost:8080/jmw/test16/init?name…