Python篇——数据结构与算法(第五部分:数据结构)

news2025/2/4 3:58:34
  • 数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成
  • 简单来说,数据结构就是设计数据以何种方式组织并存储在计算机中
  • 比如:列表、集合与字典等都是一种数据结构
  • N.Wirth:“程序 = 数据结构+算法”

1、列表

  • 列表(其他语言称数组)是一种基本数据类型
  • 关于列表的问题:
    • 列表中的元素是如何存储的?
    • 列表的基本操作:按下标查找、插入元素、删除元素.......
    • 这些操作的时间复杂度是多少?
  • 扩展:Python的列表是如何实现的?

列表是动态存储的,长度大小不固定,可以随意地增加、删减或者改变元素

元组是静态存储的,无法增删改,想要对已有的元组做任何“改变”,就只能开辟一块内存,创建新的元组

Note:

数组与列表有两点不同:

  1. 数组元素类型要相同
  2. 数组长度固定
  3. O(n)

2、栈

  • 栈(Stack)是一个数据集合,可以理解为只能在一端进行插入或删除操作的列表
  • 栈的特点:后进先出(Last in first out)
  • 栈的概念:栈顶、栈底
  • 栈的基本操作:
    • 进栈
    • 出栈
    • 取栈顶

 Note:

一般使用列表结构就可以实现栈

  • 进栈:li.append
  • 出栈:li.pop
  • 取栈顶:li[-1]
class Stack:
    def __init__(self):
        self.stack = []

    def push(self, val):
        self.stack.append(val)

    def pop(self):
        return self.stack.pop()

    def get_top(self):
        if len(self.stack) > 0:
            return self.stack[-1]
        else:
            return None


stack = Stack()
stack.push(1)
stack.push(2)
print(stack.pop())

栈的应用:括号匹配问题

class Stack:
    def __init__(self):
        self.stack = []

    def push(self, val):
        self.stack.append(val)

    def pop(self):
        return self.stack.pop()

    def get_top(self):
        if len(self.stack) > 0:
            return self.stack[-1]
        else:
            return None

    def is_empty(self):
        return len(self.stack) == 0


def brace_match(string):
    match = {')': '(', '}': '{', ']': '['}  # 键值对
    stack = Stack()
    for i in string:
        if i in {'(', '{', '['}:
            stack.push(i)
        else:
            if stack.is_empty():
                return False
            elif stack.get_top() == match[i]:
                stack.pop()
            else:
                return False
    if stack.is_empty():
        return True
    else:
        return False


print(brace_match('[{()}]'))

 2、队列

 

 队列的实现方式:环形队列

Note:

  • 为什么不用列表。因为空间浪费了。
  • 为什么队满最后一个不填元素,因为将导致无法判断是队空还是队满(rear==front)
  • 空队列rear==front ;满队列rear+1==front
  • 循环的关键点:如何使得下标11过了之后能到0 ? 取余

 总结:

  • 环形队列:当队尾指针front==Maxsize-1时,在前进一个位置就自动到0(Maxsize指的是队列长度)
  • 队首指针前进1:front=(front+1)%Maxsize
  • 队尾指针前进1:rear=(rear+1)%Maxsize
  • 队空条件:rear==front
  • 队满条件:(rear+1)%Maxsize==front
class Queue:
    def __init__(self, size=100):
        self.queue = [0 for _ in range(100)]
        self.size = size
        self.rear = 0  # 队尾
        self.front = 0  # 队首

    def push(self, element):
        '''入队'''
        if not self.is_filled():
            self.rear = (self.rear + 1) % self.size
            self.queue[self.rear] = element
        else:
            raise IndexError("Queue is filled!")

    def pop(self):
        '''出队'''
        if not self.is_empty():
            self.front = (self.front + 1) % self.size
            return self.queue[self.front]
        else:
            raise IndexError('Queue is empty!')

    def is_empty(self):
        '''判断队空'''
        return self.rear == self.front

    def is_filled(self):
        '''判断队满'''
        return self.front == (self.rear + 1) % self.size


q = Queue(size=5)
for i in range(4):  # 0,1,2,3  ; size=5 是因为判断队满的时候留了一个空位置
    q.push(i)
print(q.is_filled())

3、双向队列

 

 内置模块

# 内置模块
# collections 为结构包
from collections import deque

q = deque([1, 2, 3, 4, 5], 5)
# 单向队列
q.append(6)  # 队尾进队
print(q.popleft())  # 队首出队

# 双向队列
q.appendleft(1)  # 队首进队
print(q.popleft())  # 队首出队
q.append(2)  # 队尾入队
print(q.pop())  # 队尾出队

 结果:

2
1
2

Process finished with exit code 0

 Note:

  • 为什么第一个的输出是“2”呢?
  • 因为内置模块中如果size满了,会自动pop头元素,这里就导致我们pop的时候是元素2

应用:

如上面Note说的,如果size满了,会自动将前面的元素弹出,那么应用在哪里呢?

例如:我们先创建一个test文件,希望可以输出后面几行的内容该怎么做?

 代码如下:

def tail(n):
    with open('Queue2_test.txt', 'r') as f:
        q = deque(f, n)
        return q


print((tail(5)))

结果如下:

deque(['sbdujaodf\n', 'bsjcb\n', 'sda\n', 'cvxcvg\n', 'asd\n'], maxlen=5)

Process finished with exit code 0

这样,就使用队列完成了对文本后面几行的输出。

4、栈和队列的应用(迷宫问题)

 4.1栈——深度优先搜索

# 迷宫问题
maze = [
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 0, 0, 1, 0, 0, 0, 1, 0, 1],
    [1, 0, 0, 1, 0, 0, 0, 1, 0, 1],
    [1, 0, 0, 0, 0, 1, 1, 0, 0, 1],
    [1, 0, 1, 1, 1, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 1, 1, 1, 0, 1, 1, 0, 1],
    [1, 0, 1, 1, 1, 0, 1, 1, 0, 1],
    [1, 1, 0, 0, 0, 0, 0, 0, 0, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
]

# 新列表存储四个方向
dirs = [
    lambda x, y: (x + 1, y),
    lambda x, y: (x - 1, y),
    lambda x, y: (x, y + 1),
    lambda x, y: (x, y - 1)
]


def maze_path(x1, y1, x2, y2):
    '''
    :param x1: 起点坐标
    :param y1:
    :param x2: 终点坐标
    :param y2:
    '''
    stack = []
    stack.append((x1, y1))
    # 栈空表示没有通路
    while (len(stack) > 0):
        # 当前节点 curNode
        curNode = stack[-1]
        if curNode[0] == x2 and curNode[1] == y2:
            # 走到终点
            for p in stack:
                print(p)
            return True
        # 上(x-1)    下(x+1)  左(y-1)  右(y+1)四个方向
        for dir in dirs:
            # 下一个节点
            nextNode = dir(curNode[0], curNode[1])
            # 如果下一个节点能走
            if maze[[nextNode[0]][nextNode[1]]] == 0:
                stack.append(nextNode)
                maze[nextNode[0]][nextNode[1]] = 2  # 标记为已经走过了
                break
        # 一个都找不到
        else:
            maze[nextNode[0]][nextNode[1]] = 2
            stack.pop()
    else:
        print('None path')
        return False


maze_path(1, 1, 8, 8)

 4.2队列——广度优先搜索

from collections import deque

# 迷宫问题
maze = [
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 0, 0, 1, 0, 0, 0, 1, 0, 1],
    [1, 0, 0, 1, 0, 0, 0, 1, 0, 1],
    [1, 0, 0, 0, 0, 1, 1, 0, 0, 1],
    [1, 0, 1, 1, 1, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 1, 1, 1, 0, 1, 1, 0, 1],
    [1, 0, 1, 1, 1, 0, 1, 1, 0, 1],
    [1, 1, 0, 0, 0, 0, 0, 0, 0, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
]

# 新列表存储四个方向
dirs = [
    lambda x, y: (x + 1, y),
    lambda x, y: (x - 1, y),
    lambda x, y: (x, y + 1),
    lambda x, y: (x, y - 1)
]


def print_r(path):
    curNode = path[-1]
    realpath = []
    while curNode[2] != -1:
        realpath.append(curNode[0], curNode[1])
        curNode = curNode[2]

    # 起点
    realpath.append(curNode[0:2])
    realpath.reverse()
    for node in realpath:
        print(node)


def maze_path_queue(x1, y1, x2, y2):
    queue = deque()
    queue.append((x1, y1, -1))
    # path用于存储出队节点,方便后面查找路径
    path = []
    while len(queue) > 0:
        curNode = queue.popleft()
        path.append(curNode)
        if curNode[0] == x2 and curNode[1] == y2:
            # 终点
            print_r(path)
            return True
        for dir in dirs:
            # 搜索当前节点周围节点
            nextNode = dir(curNode[0], curNode[1])
            if maze[nextNode[0]][nextNode[1]] == 0:
                queue.append(nextNode[0], nextNode[1], len(path) - 1)
                maze[nextNode[0]][nextNode[1]] = 2  # 标记已经走过
    else:
        return False


maze_path_queue(1, 1, 8, 8)

5、链表 

 5.1创建链表

  • 头插法(要知道head在哪儿)
  • 尾插法(除了要知道head在哪儿,还要知道tail在哪儿)

头插法

# 链表
class Node:
    def __init__(self, item):
        self.item = item
        self.next = None


def creat_linklist(li):
    head = Node(li[0])
    for i in li[1:]:
        '''头插法'''
        node = Node(i)
        node.next = head
        head = node
    return head


def print_link_list(li):
    while li:
        print(li.item, end=',')
        li = li.next


li = creat_linklist([1, 2, 3, 4])
print_link_list(li)

尾插法

# 链表
class Node:
    def __init__(self, item):
        self.item = item
        self.next = None


def creat_linklist_head(li):
    head = Node(li[0])
    for i in li[1:]:
        '''头插法'''
        node = Node(i)
        node.next = head
        head = node
    return head


def print_link_list(li):
    while li:
        print(li.item, end=',')
        li = li.next


def creat_linklist_tail(li):
    head = Node(li[0])
    tail = head
    for i in li[1:]:
        node = Node(i)
        tail.next = node
        tail = node
    return head


# li = creat_linklist_head([1, 2, 3, 4])
li1 = creat_linklist_tail([1, 2, 3, 4])
# print_link_list(li)
print_link_list(li1)

5.2链表的遍历

 5.3链表的插入和删除

插入

 删除

 

 5.4双链表

 插入

删除

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

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

相关文章

如何识别二叉树的“亲戚”?——探秘判断子树的奥妙

本篇博客会讲解力扣“572. 另一棵树的子树”的解题思路,这是题目链接。先来审题: 本题的思路是:使用递归,把大问题化作小问题。 先来思考:如何判断q是不是p的子树呢? q是p的子树有3种情况,分别…

不断进化!奇点云助豫园股份构建集团统一战略的数据平台

“一张图、一颗心、一场仗,构建集团统一战略的数据平台,豫园股份不断进化。” 日前,2023 StartDT Day 数智科技大会正式举办。企业客户、行业专家、技术专家与数万位参会伙伴相聚云上,共话数据时代进化之道。 作为消费产业的数字…

Spring Cloud - Ribbon 负载均衡原理、负载策略、懒加载

目录 ​编辑 一、Ribbon 负载均衡原理 1.1、前言 1.2、负载均衡的工作流程 二、负载均衡策略 2.1、策略原理 2.2、负载均衡自定义方式 三、Ribbon 加载方式 一、Ribbon 负载均衡原理 1.1、前言 ps:案例是上一章所讲的 “根据订单id查询订单的同时&#xff0…

Matlab机器人运动学与正逆解算法学习笔记

文章目录 ※ 参考资料建立DH模型△ 基本概念和标准DH/改进DH○ 连杆与关节的编号○ 标准DH与改进DH △ DH参数模型建立方法○ 标准DH参数定义及方法简介 连杆坐标系建立方法 标准DH参数含义※ 关于DH参数以哪个轴的指向为准的问题 标准DH坐标系间的齐次变换矩阵 ○ 改进DH参数…

WPS AI内测申请窍门;AI数字人最全工具盘点;AI超级个体必读书籍;产品国际化与本地化指南;生成式AI应用路线图 | ShowMeAI日报

👀日报&周刊合集 | 🎡生产力工具与行业应用大全 | 🧡 点赞关注评论拜托啦! 🤖 生成式AI应用路线图:多模态AI的应用能力演进 随着生成式AI「对生成内容的可控性」不断提高,其应用场景也在不断…

【算法系列 | 6】深入解析排序算法之——堆排序

序言 你只管努力,其他交给时间,时间会证明一切。 文章标记颜色说明: 黄色:重要标题红色:用来标记结论绿色:用来标记一级论点蓝色:用来标记二级论点 决定开一个算法专栏,希望能帮助大…

整理 钢琴教材 铃木钢琴教程(铃木)

邮箱不能及时回复,现放到网盘里了,文末按需自取 铃木钢琴教程第1册 文件名:铃木钢琴教程第1册 超清PDF 文件大小:7.05 MB 下载地址:https://download.csdn.net/download/qq_36040764/85051148 铃木钢琴教程第2册 文件名:铃木钢琴教程第2册 超清PDF 文件大小:5.54 …

边缘检测笔记

边缘是什么? 图像的边缘是指图像局部区域中亮度变化明显的部分,边缘位于像素的灰度值产生突变的地方。 边缘的正负之分:由暗到亮为正,由亮变暗为负。 图像的高频信号和低频信号 简单理解为,图像中高频分量&#xff08…

在Windows11平台安装JDK11(双11)

目录 引言一、安装前说明1.系统要求2.多版本安装 二、JDK11安装三、安装成功验证1.验证2.Path环境变量 总结 引言 本文主要是详细讲解在 Windows 11 系统上安装 JDK 11,安装时有一些注意事项需要说明。与 JDK 8 的安装过程有少许不一样。 一、安装前说明 1.系统要…

GPT-4的中国2023高考作文

我选取2023年上海的作文题(我比较感兴趣),题目如下: 面对这个题目,不知道各位有什么想法么?如果你去考试,你会怎么写? 来,我们看看AI是怎么写的。 以下是GPT-4的作文&a…

vmware虚拟机网络“桥接模式”与“NAT模式”的联网原理及linux环境下IP配置指引

一、vmware虚拟机网络“桥接模式”与“NAT模式”的区别 选中虚拟机》设置》网络适配器,打开虚拟机设置面板 我们看到网络连接处有多个选项,今天良哥通过试验告诉你“桥接模式”和“NAT模式”的联网原理、区别及两种模式下IP地址配置的详细方法。 桥接模…

spring-data-elasticsearch.4.2.0 jar包冲突导致:StackOverflow

最近要求es做升级改造: 目前版本: 1. springframework 4.3.3-RELEASE 2. spring-data-elasticsearch: 2.0.3 3. elasticsearch: 2.4.0 4. 工具类: ElasticsearchTemplate 升级后ES版本7.10.0 1. springframework 升级到 5.3.10 2. spring-data-elasticsearch 升级到 4.…

热门bi报表软件推荐,哪款bi报表软件更功能更强大?

随着商业智能(BI)的不断发展和应用,越来越多的企业开始关注和使用BI报表软件。但是在众多的BI报表软件中,如何选择一款既功能强大又易于使用的软件,成为了许多企业和个人面临的难题。下面将为大家介绍5款热门的BI报表软…

爆肝百万字;学完这些你的python就无敌了

前言 最近高考刚刚结束,不少大学也快陆陆续续的要放暑假了,不少人表示暑假想学点python知识,或提升下自己,或打算学点技术兼职赚点零花钱,于是肝了一份Python最新学习文档总结资料 :全文档1378页&#xff…

Python的离线安装

原文链接 在没有外网的情况下,安装Python环境只能采用离线方式。 Windows离线安装Python Python离线安装包的下载地址:https://www.python.org/ftp/python/ 我选择的是:python-3.8.5-amd64.exe 双击运行安装包即可完成安装。 安装完成后…

简化本地Feign调用

在平常的工作中,OpenFeign作为微服务间的调用组件使用的非常普遍,接口配合注解的调用方式突出一个简便,让我们能无需关注内部细节就能实现服务间的接口调用。 但是工作中用久了,发现 Feign 也有些使用起来麻烦的地方,…

【Haproxy 搭建Web 群集】

目录 一、Haoroxy 基础了解1、常见的Web集群调度器2、Haproxy 应用分析 二、Haproxy 调度算法原理三、HAProxy的主要特性四、HAProxy负载均衡策略五、LVS、Nginx、HAproxy的区别1、Nginx的优点,缺点2、LVS的优点和缺点3、HAProxy的优点 六、Haproxy搭建 Web 群集实验…

跟着LearnOpenGL学习8--摄像机

文章目录 一、前言二、摄像机/观察空间2.1、摄像机位置2.2、摄像机方向2.3、右轴2.4、上轴2.5、LookAt2.6、LookAt测试 三、自由移动3.1、移动速度 四、视角移动4.1、欧拉角 五、鼠标输入5.1、缩放 六、摄像机类 一、前言 前面的教程中我们讨论了观察矩阵以及如何使用观察矩阵…

【软考系统架构师】进程与线程、并发和并行的理解

进程和线程的概念是软考里经常出现的概念,也是计算机领域的基础概念之一,看到一套非常形象的进程和线程的解释,记录一下 CPU 相当于一个工厂的能源核心,它一直运行,并向外提供动力。 什么是进程 但是这家工厂资金有限&…

A*算法与八数码问题(numpy)

努力是为了不平庸~ 学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。 目录 一、引言 二、思路 1. 确定问题和目标: 2. 确定算法和数据结构: 3. 编写代码框架 4. 实现辅助函数&#xff1…